protected override ClassDeclarationSyntax InternalExecute( ClassWithSourceCode childClass, SemanticModel semantic, Settings settings = null) { // create a field declaration and add it to the child class // check the following cases: // 1. if mixin type is a concrete type that has a parameterless constructor // if injection setting is not set => init field with new instance of type // 2. if mixin is interface or does not have a parameterless constructor // do nothing var positionOfClassInSourceFile = childClass.SourceCode.GetLocation().SourceSpan.Start; var typeSyntax = ParseTypeName( _mixin.Class.TypeSymbol.ReduceQualifiedTypeName(semantic,positionOfClassInSourceFile)); var newFieldDeclaration = FieldDeclaration( VariableDeclaration(typeSyntax) .WithVariables( SingletonSeparatedList( VariableDeclarator(_mixin.Name)))) .WithModifiers(TokenList(Token(SyntaxKind.PrivateKeyword))); var newClassDeclaration = childClass.SourceCode.AddMembers(newFieldDeclaration); return newClassDeclaration; }
private async Task<Solution> CreateMixin( IMixinCommand mixinCommand, Document document, ClassWithSourceCode childClass, CancellationToken cancellationToken) { // get service provider and read settings from storage var serviceProvider = Microsoft.VisualStudio.Shell.ServiceProvider.GlobalProvider; var settings = new Settings(serviceProvider); var model = await document.GetSemanticModelAsync(cancellationToken); if (mixinCommand.CanExecute(childClass,settings)) { // execute the command => we get a new class declaration var newClassDeclaration = mixinCommand.Execute(childClass.SourceCode, model,settings); // replace the old class declaration in the syntax tree var root = await model.SyntaxTree.GetRootAsync(cancellationToken); var newRoot = root.ReplaceNode(childClass.SourceCode, newClassDeclaration); // create a new document from the new syntax tree var newDocument = document.WithSyntaxRoot(newRoot); return newDocument.Project.Solution; } return null; }
public override bool CanExecute(ClassWithSourceCode childClass, Settings settings = null) { if (settings == null || !settings.InjectMixins) return false; return !(childClass.AllConstructorsHaveParameter(_mixin.Name.ConvertFieldNameToParameterName()) && childClass.HasConstructor); }
public override bool CanExecute(ClassWithSourceCode childClass, Settings settings = null) { // this feature is only available if the mixin class is an interface if (Mixin == null || !Mixin.Class.IsInterface) return false; return base.CanExecute(childClass, settings); }
protected override ClassDeclarationSyntax InternalExecute( ClassWithSourceCode childClass, SemanticModel semantic, Settings settings = null) { var constructorSyntaxWriter = new ConstructorInjectionSyntaxWriter(_mixin, semantic); var classDeclaration = (ClassDeclarationSyntax)constructorSyntaxWriter.Visit(childClass.SourceCode); return classDeclaration; }
public override bool CanExecute( ClassWithSourceCode childClass, Settings settings = null) { // ensure that the child class does not already have a // reference to the mixin with the given name var mixinField = childClass.SourceCode.FindMixinReference(_mixin.Name); return mixinField == null; }
/// <summary> /// Template method that checks if command can be executed and if yes, /// executes the command. Otherwise the original source code of the child is returned. /// </summary> /// <param name="semantic">semantic model of the child's and mixin's source code</param> /// <param name="settings">optional settings object</param> /// <returns>the modified class declaration of the child class after executing /// the command or the original child's source code if command could not be /// executed</returns> public ClassDeclarationSyntax Execute( ClassDeclarationSyntax childDeclaration, SemanticModel semantic, Settings settings = null) { var childClass = new ClassFactory(semantic).Create(childDeclaration); if (CanExecute(childClass, settings)) return InternalExecute(childClass, semantic, settings); return childClass.SourceCode; }
public virtual bool CanExecute(ClassWithSourceCode childClass, Settings settings = null) { if (Mixin == null) return false; var canExecute = false; // check that at least one command is executable foreach (var command in _commands) canExecute = canExecute || command.CanExecute(childClass, settings); return canExecute; }
public IncludeMixinSyntaxWriter( IEnumerable<Member> membersToImplement, MixinReference mixin, SemanticModel semanticModel, Settings settings = null) { _members = membersToImplement; _mixin = mixin; _semantic = semanticModel; _settings = settings ?? new Settings(); }
protected override ClassDeclarationSyntax InternalExecute( ClassWithSourceCode childClass, SemanticModel semantic, Settings settings = null) { var classDeclaration = childClass.SourceCode; var positionInSource = classDeclaration.GetLocation().SourceSpan.Start; var interfaceWriter = new AddInterfacesToChildSyntaxWriter(_mixin, semantic, positionInSource); classDeclaration = (ClassDeclarationSyntax)interfaceWriter.Visit(classDeclaration); return classDeclaration; }
/// <summary> /// method is virtual, so derived classes can override it to create /// different strategies (e.g. for testing) /// </summary> /// <param name="mixin"></param> /// <param name="semantic"></param> /// <param name="settings"></param> /// <returns></returns> protected virtual Dictionary<Type, IImplementMemberForwarding> CreateStrategies( MixinReference mixin, SemanticModel semantic, Settings settings) { var implementationStrategies = new Dictionary<Type, IImplementMemberForwarding> { [typeof(Method)] = new ImplementMethodForwarding(mixin, _semantic, _settings), [typeof(IndexerProperty)] = new ImplementIndexerForwarding(mixin, _semantic, _settings), [typeof(Property)] = new ImplementPropertyForwarding(mixin, _semantic, _settings), [typeof(Event)] = new ImplementEventForwarding(mixin,_semantic,_settings) }; return implementationStrategies; }
public override bool CanExecute(ClassWithSourceCode childClass, Settings settings = null) { if (_mixin == null || childClass == null) return false; // do the mixin operation the first time if (_mixer == null) { _mixer = new Mixer(); _mixer.IncludeMixinInChild(_mixin, childClass); } // command can be executed if we either have to forward members or extend a constructor return _mixer.MembersToImplement.Any(); }
protected override ClassDeclarationSyntax InternalExecute( ClassWithSourceCode childClass, SemanticModel semantic, Settings settings = null) { var syntaxWriter = new IncludeMixinSyntaxWriter( _mixer.MembersToImplement, _mixin, semantic, settings); var classDeclaration = (ClassDeclarationSyntax)syntaxWriter.Visit(childClass.SourceCode); return classDeclaration; }
public sealed override async Task ComputeRefactoringsAsync(CodeRefactoringContext context) { var root = await context.Document.GetSyntaxRootAsync(context.CancellationToken).ConfigureAwait(false); // Find the node at the selection. var node = root.FindNode(context.Span); var model = await context.Document.GetSemanticModelAsync(context.CancellationToken).ConfigureAwait(false); CompositeCommand command = null; // create mixin from base type var baseTypeSyntax = node as SimpleBaseTypeSyntax; // create command depending on the selected node if (baseTypeSyntax != null) { command = new CreateMixinFromInterfaceCommand(baseTypeSyntax, model); } else { var fieldDeclarationNode = GetContainingFieldDeclaration(node); if (fieldDeclarationNode != null) command = new CreateMixinFromFieldDeclarationCommand(fieldDeclarationNode, model); } if (command == null) return; // get service provider and read settings from storage var serviceProvider = Microsoft.VisualStudio.Shell.ServiceProvider.GlobalProvider; var settings = new Settings(serviceProvider); var childClassDeclaration = node.FindContainingClass(); var childClass = new ClassFactory(model).Create(childClassDeclaration); if (!command.CanExecute(childClass, settings)) return; var action = CodeAction.Create( command.Title, c => CreateMixin(command, context.Document, childClass, c)); // Register this code action. context.RegisterRefactoring(action); }
public ClassDeclarationSyntax Execute( ClassDeclarationSyntax childDeclaration, SemanticModel semantic, Settings settings = null) { // we need the class name of the child to find it in the syntax tree // after it was changed var childClassName = childDeclaration.Identifier.Text.ToString(); foreach (var command in _commands) { var oldSyntaxTree = childDeclaration.SyntaxTree; var newChildDeclaration = command.Execute(childDeclaration, semantic, settings); // replace the old class declaration with the new one in the syntax tree var newRoot = semantic.SyntaxTree.GetRoot().ReplaceNode(childDeclaration, newChildDeclaration); var newSyntaxTree = newRoot.SyntaxTree; var compilation = semantic.Compilation.ReplaceSyntaxTree(oldSyntaxTree,newSyntaxTree); // after creating the new syntax tree, get a new semantic model semantic = compilation.GetSemanticModel(newSyntaxTree); // also retrieve the class declaration from the new syntax tree childDeclaration = newRoot.FindClassByName(childClassName); } return childDeclaration; }
/// <summary> /// executes the command on the given child class. /// Logic of command execution must be implemented in derived classes. /// </summary> /// <param name="semantic">semantic model of the child's and mixin's source code</param> /// <param name="settings">optional settings object</param> /// <returns></returns> protected abstract ClassDeclarationSyntax InternalExecute( ClassWithSourceCode childClass, SemanticModel semantic, Settings settings = null);
/// <summary> /// called to check if the command can be executed. /// </summary> /// <param name="settings">optional settings</param> /// <returns>true if the command can be executed, otherwise false</returns> public abstract bool CanExecute( ClassWithSourceCode childClass, Settings settings = null);
public override bool CanExecute(ClassWithSourceCode childClass, Settings settings = null) { return settings != null && settings.AddInterfacesToChild; }