public void IncludeMixinInChild(MixinReference mixin, ClassWithSourceCode child) { var childMembers = child.MembersFromThisAndBase; var mixinMembers = mixin.Class.MembersFromThisAndBase; foreach(var mixinMember in mixinMembers) { var membersWithSameSignatureInChild = childMembers .Where(x => _memberCompare.IsSameAs(x, mixinMember)) .ToList(); // 1. case: method does not exist in child => implement it if (!membersWithSameSignatureInChild.Any()) _membersToImplement.Add(mixinMember.Clone()); else // 2. case: method does exist in child, but is abstract and not overridden => override it { // member is declared as abstract in a base class of child // but not in child itself var abstractMembers = membersWithSameSignatureInChild .Where(x => x.IsAbstract && x.Class != child && !child.HasOverride(x)); _membersToImplement.AddRange(abstractMembers.Select(x => x.Clone(true))); } } }
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) { // 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); }
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 void Setup() { _child = Substitute.For<ClassWithSourceCode>(); _mixin = Substitute.For<MixinReference>(); _mixin.Name.Returns(x => "_mixin"); _command = new InjectMixinsIntoChildCommand(_mixin); }
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; }
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 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; }
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; }
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 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(); }
public ClassWithSourceCode Create(ClassDeclarationSyntax classDeclaration) { var @class = new ClassWithSourceCode(classDeclaration) { Name = classDeclaration.Identifier.ToString() }; // create readers for reading syntax members var syntaxReaders = new SyntaxWalkerWithSemantic[] { new PropertySyntaxReader(@class, _semantic), new MethodSyntaxReader(@class, _semantic), new EventSyntaxReader(@class, _semantic), new BaseClassSyntaxReader(@class, _semantic), new InterfaceSyntaxReader(@class.Interfaces, _semantic), new ConstructorSyntaxReader(@class, _semantic) }; foreach (var syntaxReader in syntaxReaders) syntaxReader.Visit(classDeclaration); return @class; }
/// <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; }