stores the settings for the code generation. The settings can be set via an options dialog.
        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;
 }
示例#7
0
 /// <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;
 }
示例#8
0
 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;
 }
示例#12
0
        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();
        }
示例#13
0
        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);
        }
示例#15
0
 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;
 }
示例#16
0
 /// <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);
示例#17
0
 /// <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;
 }