예제 #1
0
        public static void AddUsing(DocumentEditor editor, string namespaceName, int position)
        {
            var compUnit = editor.OriginalRoot as Microsoft.CodeAnalysis.CSharp.Syntax.CompilationUnitSyntax;

            if (compUnit == null)
            {
                return;
            }

            if (compUnit.Usings.Any(u => u.Name.GetText().ToString() == namespaceName))
            {
                return;
            }

            if (position >= 0)
            {
                var enclosingSymbol = editor.SemanticModel.GetEnclosingSymbol(position);
                if (enclosingSymbol != null)
                {
                    var nsEnclName = enclosingSymbol.ContainingNamespace.ToString();
                    if (nsEnclName.StartsWith(namespaceName + ".") || nsEnclName == namespaceName)
                    {
                        return;
                    }
                }
            }


            var usingDirective = editor.Generator.NamespaceImportDeclaration(namespaceName);

            editor.InsertAfter(compUnit.Usings.Last(), usingDirective);
        }
        private void ReplaceImportStatements()
        {
            HashSet <string> alreadyAddedImportsStatements             = new HashSet <string>();
            IEnumerable <ImportsStatementSyntax> importsStatementNodes = tree.GetRoot().DescendantNodes().OfType <ImportsStatementSyntax>();

            foreach (ImportsStatementSyntax oldImportsStatementNode in importsStatementNodes) // iterate over all qualified names in the file
            {
                // could be problems if this import statement isn't simple, however even if an alias is used in the import it's still simple
                SimpleImportsClauseSyntax oldSimpleImportsNode = oldImportsStatementNode.DescendantNodes().OfType <SimpleImportsClauseSyntax>().First();
                var oldNamespace = oldSimpleImportsNode.WithoutTrivia().Name.GetText().ToString();
                List <namespace_map> namespaces = NSMappingSQLConnector.GetInstance().GetNamespaceMapsFromOldNamespace(TransformProject.sdkId, oldNamespace);
                if (namespaces != null)
                {
                    foreach (namespace_map nsMap in namespaces)
                    {
                        var newNamespace = nsMap.new_namespace;
                        if (!alreadyAddedImportsStatements.Contains(newNamespace))
                        {
                            alreadyAddedImportsStatements.Add(newNamespace);
                            NameSyntax newIdentifierNode    = IdentifierName(newNamespace);
                            var        newSimpleImportsNode = oldSimpleImportsNode.WithName(newIdentifierNode);
                            SeparatedSyntaxList <ImportsClauseSyntax> simpleImportsList = new SeparatedSyntaxList <ImportsClauseSyntax>().Add(newSimpleImportsNode);
                            ImportsStatementSyntax newImportsStatementNode = ImportsStatement(simpleImportsList).WithTriviaFrom(oldImportsStatementNode);
                            newImportsStatementNode = newImportsStatementNode.WithImportsKeyword(oldImportsStatementNode.ImportsKeyword);
                            documentEditor.InsertAfter(oldImportsStatementNode, newImportsStatementNode);
                        }
                    }
                    documentEditor.RemoveNode(oldImportsStatementNode);
                }
            }
        }
예제 #3
0
        internal static void AddField(this DocumentEditor editor, TypeDeclarationSyntax containingType, FieldDeclarationSyntax field)
        {
            FieldDeclarationSyntax existing = null;

            foreach (var member in containingType.Members)
            {
                if (member is FieldDeclarationSyntax fieldDeclaration)
                {
                    if (IsInsertBefore(fieldDeclaration))
                    {
                        editor.InsertBefore(fieldDeclaration, field);
                        return;
                    }

                    existing = fieldDeclaration;
                    continue;
                }

                editor.InsertBefore(member, field);
                return;
            }

            if (existing != null)
            {
                editor.InsertAfter(existing, field);
            }
            else
            {
                editor.AddMember(containingType, field);
            }
        }
        private void ReplaceUsingStatements()
        {
            HashSet <string> alreadyAddedUsingStatements           = new HashSet <string>();
            IEnumerable <UsingDirectiveSyntax> usingDirectiveNodes = tree.GetRoot().DescendantNodes().OfType <UsingDirectiveSyntax>();

            foreach (UsingDirectiveSyntax oldUsingDirectiveNode in usingDirectiveNodes) // iterate over all qualified names in the file
            {
                var oldNamespace = oldUsingDirectiveNode.Name.GetText().ToString();
                List <namespace_map> namespaces = NSMappingSQLConnector.GetInstance().GetNamespaceMapsFromOldNamespace(TransformProject.sdkId, oldNamespace);
                if (namespaces != null)
                {
                    foreach (namespace_map nsMap in namespaces)
                    {
                        var newNamespace = nsMap.new_namespace;
                        if (!alreadyAddedUsingStatements.Contains(newNamespace))
                        {
                            alreadyAddedUsingStatements.Add(newNamespace);
                            NameSyntax newIdentifierNode     = IdentifierName(newNamespace);
                            var        newUsingDirectiveNode = oldUsingDirectiveNode.WithName(newIdentifierNode);
                            documentEditor.InsertAfter(oldUsingDirectiveNode, newUsingDirectiveNode);
                        }
                    }
                    documentEditor.RemoveNode(oldUsingDirectiveNode);
                }
            }
        }
        /// <summary>
        /// Move <paramref name="toMove"></paramref> before <paramref name="statement">.</paramref>.
        /// </summary>
        /// <param name="editor">The <see cref="DocumentEditor"/>.</param>
        /// <param name="toMove">The <see cref="StatementSyntax"/> to move.</param>
        /// <param name="statement">The <see cref="StatementSyntax"/>.</param>
        /// <returns>The <see cref="DocumentEditor"/> that was passed in.</returns>
        public static DocumentEditor MoveAfter(this DocumentEditor editor, StatementSyntax toMove, StatementSyntax statement)
        {
            if (editor is null)
            {
                throw new ArgumentNullException(nameof(editor));
            }

            if (toMove is null)
            {
                throw new ArgumentNullException(nameof(toMove));
            }

            if (statement is null)
            {
                throw new ArgumentNullException(nameof(statement));
            }

            editor.RemoveNode(toMove);
            editor.InsertAfter(statement, ToMove());
            return(editor);

            StatementSyntax ToMove()
            {
                if (statement.GetLastToken().IsKind(SyntaxKind.CloseBraceToken))
                {
                    return(toMove.WithLeadingLineFeed());
                }

                return(toMove);
            }
        }
예제 #6
0
        public static void AddImportIfNeeded(this DocumentEditor editor, string importedNamespace)
        {
            if (importedNamespace.Contains("."))
            {
                throw new NotSupportedException("Only adding of toplevel namespace is supported");
            }

            var root   = editor.OriginalRoot;
            var usings = root.DescendantNodes <UsingDirectiveSyntax>()
                         .ToArray();

            var existingImport = usings
                                 .SelectMany(u => u.DescendantNodes <IdentifierNameSyntax>())
                                 .Where(ins => ins.Parent is UsingDirectiveSyntax)
                                 .FirstOrDefault(ins => ins.Identifier.Text == importedNamespace);

            if (existingImport != null)
            {
                return;
            }

            var newSystemImport = SyntaxFactory.UsingDirective(SyntaxFactory.IdentifierName(Constants.System));

            editor.InsertAfter(usings.Last(), new[] { newSystemImport });
        }
예제 #7
0
        private static void Append(DocumentEditor editor, SyntaxNode lastNode, INamespaceSymbol[] namespaces, int startIndex)
        {
            var g = editor.Generator;

            for (int i = namespaces.Length - 1; i >= startIndex; i--)
            {
                var namespaceSymbol = namespaces[i];
                var newNode         = g.GenerateNamespaceImportDeclaration(namespaceSymbol);
                editor.InsertAfter(lastNode, newNode);
            }
        }
예제 #8
0
        private static void MakeNotify(DocumentEditor editor, ExpressionSyntax assignment, string propertyName, IMethodSymbol invoker, bool usesUnderscoreNames)
        {
            var snippet =
                assignment.FirstAncestor <PropertyDeclarationSyntax>() is PropertyDeclarationSyntax
                propertyDeclaration &&
                propertyDeclaration.Identifier.ValueText == propertyName
                    ? Snippet.OnPropertyChanged(invoker, propertyName, usesUnderscoreNames)
                    : Snippet.OnOtherPropertyChanged(invoker, propertyName, usesUnderscoreNames);

            var onPropertyChanged = SyntaxFactory.ParseStatement(snippet)
                                    .WithSimplifiedNames()
                                    .WithLeadingElasticLineFeed()
                                    .WithTrailingElasticLineFeed()
                                    .WithAdditionalAnnotations(Formatter.Annotation);

            if (assignment.Parent is AnonymousFunctionExpressionSyntax anonymousFunction)
            {
                if (anonymousFunction.Body is BlockSyntax block)
                {
                    if (block.Statements.Count > 1)
                    {
                        var previousStatement = InsertAfter(block, block.Statements.Last(), invoker);
                        editor.InsertAfter(previousStatement, new[] { onPropertyChanged });
                    }

                    return;
                }

                var expressionStatement = (ExpressionStatementSyntax)editor.Generator.ExpressionStatement(anonymousFunction.Body);
                var withStatements      = editor.Generator.WithStatements(anonymousFunction, new[] { expressionStatement, onPropertyChanged });
                editor.ReplaceNode(anonymousFunction, withStatements);
            }
            else if (assignment.Parent is ExpressionStatementSyntax assignStatement &&
                     assignStatement.Parent is BlockSyntax assignBlock)
            {
                var previousStatement = InsertAfter(assignBlock, assignStatement, invoker);
                editor.InsertAfter(previousStatement, new[] { onPropertyChanged });
            }
예제 #9
0
            public override void VisitClassDeclaration(ClassDeclarationSyntax node)
            {
                var modifiers = GetModifiers(Command.Modifiers, Command.Abstract, Command.Static, Command.Partial);
                var baseTypes = GetBaseTypes(Command.ImplementedInterfaces, Command.InheritsType);

                var classNode = node.WithIdentifier(SyntaxFactory.Identifier(Command.Name))
                                .WithTypeParameterList(Command.GenericParameters)
                                .WithConstraintClauses(Command.GenericParametersConstraints)
                                .WithAttributeLists(Command.Attributes)
                                .WithModifiers(modifiers)
                                .WithBaseList(baseTypes)
                                .WithAdditionalAnnotations(new SyntaxAnnotation($"{Id}"));

                DocumentEditor.InsertAfter(node, classNode);
            }
예제 #10
0
        private static void ChangeEventToPublicAndNonStatic(
            ICodeGenerationService codeGenerationService,
            DocumentEditor editor,
            IEventSymbol eventSymbol,
            SyntaxNode eventDeclaration,
            DeclarationModifiers modifiers
            )
        {
            var declaration = editor.Generator.GetDeclaration(eventDeclaration);
            var isEventHasExplicitAddOrRemoveMethod =
                (eventSymbol.AddMethod != null && !eventSymbol.AddMethod.IsImplicitlyDeclared) ||
                (
                    eventSymbol.RemoveMethod != null &&
                    !eventSymbol.RemoveMethod.IsImplicitlyDeclared
                );

            // There are three situations here:
            // 1. Single Event.
            // 2. Several events exist in one declaration.
            // 3. Event has add or remove method(user declared).
            // For situation 1, declaration is EventFieldDeclaration, eventDeclaration is variableDeclaration.
            // For situation 2, declaration and eventDeclaration are both EventDeclaration, which are same.
            // For situation 3, it is same as situation 2, but has add or remove method.
            if (declaration.Equals(eventDeclaration) && !isEventHasExplicitAddOrRemoveMethod)
            {
                // Several events are declared in same line
                var publicAndNonStaticSymbol = CodeGenerationSymbolFactory.CreateEventSymbol(
                    eventSymbol,
                    accessibility: Accessibility.Public,
                    modifiers: modifiers
                    );
                var options = new CodeGenerationOptions(generateMethodBodies: false);
                var publicAndNonStaticSyntax = codeGenerationService.CreateEventDeclaration(
                    publicAndNonStaticSymbol,
                    destination: CodeGenerationDestination.ClassType,
                    options: options
                    );
                // Insert a new declaration and remove the original declaration
                editor.InsertAfter(declaration, publicAndNonStaticSyntax);
                editor.RemoveNode(eventDeclaration);
            }
            else
            {
                // Handle both single event and event has add or remove method
                editor.SetAccessibility(declaration, Accessibility.Public);
                editor.SetModifiers(declaration, modifiers);
            }
        }
예제 #11
0
        public static void AddUsingIfDoesntExists(this DocumentEditor documentEditor, string usingname)
        {
            var root            = documentEditor.GetChangedDocument().GetSyntaxTreeAsync().Result.GetRoot();
            var usingStatements = root.DescendantNodes().OfType <UsingDirectiveSyntax>().ToArray();

            if (usingStatements.Length == 0)
            {
                return;
            }

            if (usingStatements.All(x => x.Name.ToString() != usingname))
            {
                var usingFluientStatment = SyntaxFactory.UsingDirective(SyntaxFactory.IdentifierName(usingname)).NormalizeWhitespace().WithTrailingTrivia(SyntaxFactory.Whitespace("\r\n"));
                documentEditor.InsertAfter(usingStatements.Last(), usingFluientStatment);
            }
        }
        private static void CreateTearDownMethod(DocumentEditor editor, ISymbol fieldOrProperty, MethodDeclarationSyntax setupMethod, QualifiedType tearDownType, CancellationToken cancellationToken)
        {
            var code = StringBuilderPool.Borrow()
                       .AppendLine($"[{tearDownType.FullName}]")
                       .AppendLine($"public void {tearDownType.Type.Replace("Attribute", string.Empty)}()")
                       .AppendLine("{")
                       .AppendLine($"    {Snippet.DisposeStatement(fieldOrProperty, editor.SemanticModel, cancellationToken)}")
                       .AppendLine("}")
                       .Return();
            var tearDownMethod = Parse.MethodDeclaration(code)
                                 .WithSimplifiedNames()
                                 .WithLeadingTrivia(SyntaxFactory.ElasticMarker)
                                 .WithTrailingTrivia(SyntaxFactory.ElasticMarker)
                                 .WithAdditionalAnnotations(Formatter.Annotation);

            editor.InsertAfter(setupMethod, tearDownMethod);
        }
예제 #13
0
        private static void GenerateRegistrationStatement(DocumentEditor editor, ClassBlockSyntax classDeclaration, ConstructorBlockSyntax staticConstructor,
                                                          string registerPropertyMethodName, IPropertySymbol propertySymbol, bool returnsMounter, CancellationToken ct)
        {
            var semanticModel = editor.SemanticModel;
            var classSymbol   = semanticModel.GetDeclaredSymbol(classDeclaration, ct);

            var statements = staticConstructor.Statements;

            if (statements.Count > 0)
            {
                var statement = editor.Generator.GeneratePropertyRegistration(LanguageNames.VisualBasic, classSymbol, propertySymbol, registerPropertyMethodName, returnsMounter, true);
                editor.InsertAfter(statements.Last(), new SyntaxNode[] { statement });
            }
            else
            {
                var newStaticConstructor = editor.Generator.GeneratePropertyRegistration(LanguageNames.VisualBasic, classSymbol, propertySymbol, registerPropertyMethodName, returnsMounter, false);
                editor.ReplaceNode(staticConstructor, newStaticConstructor);
            }
        }
        private static void AddToIf(DocumentEditor editor, IfStatementSyntax ifSetAndRaise, ExpressionStatementSyntax invocation)
        {
            if (ifSetAndRaise.Statement is BlockSyntax body)
            {
                editor.RemoveNode(invocation);
                if (body.Statements.Count == 0)
                {
                    editor.ReplaceNode(
                        body,
                        body.AddStatements(invocation.WithLeadingElasticLineFeed()));
                }
                else
                {
                    editor.InsertAfter(body.Statements.Last(), invocation.WithLeadingElasticLineFeed());
                }
            }
            else
            {
                if (ifSetAndRaise.Statement == null)
                {
                    editor.RemoveNode(invocation);
                    editor.ReplaceNode(
                        ifSetAndRaise,
                        (x, _) => ((IfStatementSyntax)x)
                        .WithStatement(SyntaxFactory.Block(ifSetAndRaise.Statement, invocation))
                        .WithSimplifiedNames()
                        .WithTrailingElasticLineFeed()
                        .WithAdditionalAnnotations(Formatter.Annotation));
                }
                else
                {
                    editor.RemoveNode(invocation);
                    editor.ReplaceNode(
                        ifSetAndRaise.Statement,
                        (x, _) => SyntaxFactory.Block(ifSetAndRaise.Statement, invocation)
                        .WithSimplifiedNames()
                        .WithTrailingElasticLineFeed()
                        .WithAdditionalAnnotations(Formatter.Annotation));
                }
            }

            editor.FormatNode(ifSetAndRaise);
        }
        /// <summary>
        /// Move <paramref name="toMove"></paramref> before <paramref name="member">.</paramref>.
        /// </summary>
        /// <param name="editor">The <see cref="DocumentEditor"/>.</param>
        /// <param name="toMove">The <see cref="MemberDeclarationSyntax"/> to move.</param>
        /// <param name="member">The <see cref="MemberDeclarationSyntax"/>.</param>
        /// <returns>The <see cref="DocumentEditor"/> that was passed in.</returns>
        public static DocumentEditor MoveAfter(this DocumentEditor editor, MemberDeclarationSyntax toMove, MemberDeclarationSyntax member)
        {
            if (editor is null)
            {
                throw new ArgumentNullException(nameof(editor));
            }

            if (toMove is null)
            {
                throw new ArgumentNullException(nameof(toMove));
            }

            if (member is null)
            {
                throw new ArgumentNullException(nameof(member));
            }

            editor.RemoveNode(toMove);
            editor.InsertAfter(member, ToMove());
            editor.ReplaceNode(member, Member());
            return(editor);

            MemberDeclarationSyntax ToMove()
            {
                return(toMove.AdjustLeadingNewLine(member));
            }

            MemberDeclarationSyntax Member()
            {
                if (member.Parent is TypeDeclarationSyntax typeDeclaration)
                {
                    var index = typeDeclaration.Members.IndexOf(member) - 1;
                    if (typeDeclaration.Members.IndexOf(toMove) == index)
                    {
                        index--;
                    }

                    return(member.AdjustLeadingNewLine(typeDeclaration.Members.ElementAtOrDefault(index)));
                }

                return(toMove);
            }
        }
예제 #16
0
            public override void VisitPropertyDeclaration(PropertyDeclarationSyntax node)
            {
                var modifiers = GetModifiers(Command.Modifiers, Command.Abstract, Command.Static);

                var newNode = node.WithIdentifier(SyntaxFactory.ParseToken(Command.Name))
                              .WithAttributeLists(Command.Attributes)
                              .WithModifiers(modifiers)
                              .WithAdditionalAnnotations(new SyntaxAnnotation($"{Id}"))
                              .WithType(Command.ReturnType ?? node.Type);

                if (Command.InitializerExpression != null)
                {
                    newNode = newNode.WithInitializer(SyntaxFactory.EqualsValueClause(Command.InitializerExpression))
                              .WithSemicolonToken(SyntaxFactory.Token(SyntaxKind.SemicolonToken));
                }

                var getAccessor = node.AccessorList.Accessors.FirstOrDefault(x => x.IsKind(SyntaxKind.GetAccessorDeclaration));
                var setAccessor = node.AccessorList.Accessors.FirstOrDefault(x => x.IsKind(SyntaxKind.SetKeyword));

                var newGetAccessor = getAccessor?.WithModifiers(Command.GetModifier)
                                     .WithExpressionBody(Command.GetExpression ?? getAccessor?.ExpressionBody)
                                     .WithBody(Command.GetStatements ?? getAccessor?.Body);

                var newSetAccessor = setAccessor?.WithModifiers(Command.SetModifier)
                                     .WithExpressionBody(Command.SetExpression ?? setAccessor?.ExpressionBody)
                                     .WithBody(Command.SetStatements ?? setAccessor?.Body);


                var Accesors = new SyntaxList <AccessorDeclarationSyntax>();

                if (newGetAccessor != null)
                {
                    Accesors = Accesors.Add(newGetAccessor);
                }
                if (newSetAccessor != null)
                {
                    Accesors = Accesors.Add(newSetAccessor);
                }
                newNode = newNode.WithAccessorList(SyntaxFactory.AccessorList(Accesors));

                DocumentEditor.InsertAfter(node, newNode);
            }
예제 #17
0
        private static void MakeWithBackingFieldNotify(DocumentEditor editor, PropertyDeclarationSyntax propertyDeclaration, IMethodSymbol invoker, SemanticModel semanticModel, CancellationToken cancellationToken)
        {
            var classDeclaration = propertyDeclaration.FirstAncestorOrSelf <ClassDeclarationSyntax>();

            if (classDeclaration == null)
            {
                return;
            }

            if (IsSimpleAssignmentOnly(propertyDeclaration, out var setter, out var statement, out var assignment, out _))
            {
                var underscoreFields = CodeStyle.UnderscoreFields(semanticModel);
                var property         = semanticModel.GetDeclaredSymbolSafe(propertyDeclaration, cancellationToken);
                var notifyStatement  = SyntaxFactory
                                       .ParseStatement(Snippet.OnPropertyChanged(invoker, property.Name, underscoreFields))
                                       .WithLeadingTrivia(SyntaxFactory.ElasticMarker)
                                       .WithTrailingTrivia(SyntaxFactory.ElasticMarker)
                                       .WithSimplifiedNames()
                                       .WithAdditionalAnnotations(Formatter.Annotation);
                if (setter.ExpressionBody != null)
                {
                    editor.ReplaceNode(
                        setter,
                        (x, _) =>
                    {
                        var old = (AccessorDeclarationSyntax)x;
                        return(old.WithBody(
                                   SyntaxFactory.Block(
                                       SyntaxFactory.ExpressionStatement(assignment),
                                       notifyStatement))
                               .WithExpressionBody(null)
                               .WithSemicolonToken(SyntaxFactory.Token(SyntaxKind.None)));
                    });
                    editor.FormatNode(propertyDeclaration);
                }
                else if (setter.Body != null)
                {
                    editor.InsertAfter(statement, notifyStatement);
                    editor.FormatNode(propertyDeclaration);
                }
            }
        }
예제 #18
0
            public override void VisitConstructorDeclaration(ConstructorDeclarationSyntax node)
            {
                var modifiers = GetModifiers(Command.Modifiers, Command.Static);

                var ConstructorNode = node.WithIdentifier((Command.OnNode as TypeDeclarationSyntax)?.Identifier ?? node.Identifier)
                                      .WithAttributeLists(Command.Attributes.Count > 0 ? Command.Attributes : node.AttributeLists)
                                      .WithParameterList(Command.Parameters ?? node.ParameterList)
                                      .WithBody(Command.BlockBody ?? node.Body)
                                      .WithModifiers(modifiers.Count > 0 ? modifiers : node.Modifiers)
                                      .WithAdditionalAnnotations(new SyntaxAnnotation($"{Id}"));

                if (Command.OnNode is null)
                {
                    DocumentEditor.InsertAfter(node, ConstructorNode);
                }
                else
                {
                    DocumentEditor.InsertMembers(Command.OnNode, 0, new[] { ConstructorNode });
                }
            }
예제 #19
0
            public override void VisitMethodDeclaration(MethodDeclarationSyntax node)
            {
                var modifiers = GetModifiers(Command.Modifiers, Command.Abstract, Command.Static, Command.Partial);

                var methodNode = node.WithIdentifier(SyntaxFactory.ParseToken(Command.Name ?? node.Identifier.ToString()))
                                 .WithAttributeLists(Command.Attributes.Count > 0 ? Command.Attributes : node.AttributeLists)
                                 .WithParameterList(Command.Parameters ?? node.ParameterList)
                                 .WithTypeParameterList(Command.GenericParameters ?? node.TypeParameterList)
                                 .WithConstraintClauses(Command.GenericParametersConstraints.Count > 0 ? Command.GenericParametersConstraints : node.ConstraintClauses)
                                 .WithModifiers(modifiers.Count > 0 ? modifiers : node.Modifiers)
                                 .WithReturnType(Command.ReturnType ?? node.ReturnType)
                                 .WithBody(Command.BlockBody ?? (Command.ExpressionBody is null ? node.Body: null))
                                 .WithExpressionBody(Command.ExpressionBody ?? (Command.BlockBody is null ? node.ExpressionBody : null))
                                 .WithAdditionalAnnotations(new SyntaxAnnotation($"{Id}"));

                if (Command.ExpressionBody != null)
                {
                    methodNode = methodNode.WithSemicolonToken(SyntaxFactory.Token(SyntaxKind.SemicolonToken));
                }

                DocumentEditor.InsertAfter(node, methodNode);
            }
예제 #20
0
 private static void GenerateRegisterChildModel(DocumentEditor editor, ConstructorBlockSyntax staticConstructor, ClassBlockSyntax classDeclaration,
                                                SemanticModel semanticModel, IPropertySymbol childProperty, IPropertySymbol foreignKey)
 {
     if (staticConstructor == null)
     {
         var newStaticConstructor = editor.Generator.GenerateChildModelRegistrationStaticConstructor(LanguageNames.VisualBasic, childProperty, foreignKey);
         var index = GetMounterDeclarationInsertIndex(classDeclaration, semanticModel);
         editor.InsertMembers(classDeclaration, index, new SyntaxNode[] { newStaticConstructor });
     }
     else
     {
         var statements = staticConstructor.Statements;
         if (statements.Count > 0)
         {
             var statement = editor.Generator.GenerateChildModelRegistration(LanguageNames.VisualBasic, childProperty, foreignKey);
             editor.InsertAfter(statements.Last(), new SyntaxNode[] { statement });
         }
         else
         {
             var newStaticConstructor = editor.Generator.GenerateChildModelRegistrationStaticConstructor(LanguageNames.VisualBasic, childProperty, foreignKey);
             editor.ReplaceNode(staticConstructor, newStaticConstructor);
         }
     }
 }
예제 #21
0
        private static void MakeWithBackingFieldNotifyWhenValueChanges(DocumentEditor editor, PropertyDeclarationSyntax propertyDeclaration, IMethodSymbol invoker, SemanticModel semanticModel, CancellationToken cancellationToken)
        {
            var classDeclaration = propertyDeclaration.FirstAncestorOrSelf <ClassDeclarationSyntax>();

            if (classDeclaration == null)
            {
                return;
            }

            if (propertyDeclaration.TryGetSetter(out var setter))
            {
                if (setter.ExpressionBody != null &&
                    IsSimpleAssignmentOnly(propertyDeclaration, out _, out _, out var assignment, out _))
                {
                    var property         = semanticModel.GetDeclaredSymbolSafe(propertyDeclaration, cancellationToken);
                    var underscoreFields = CodeStyle.UnderscoreFields(semanticModel);
                    var code             = StringBuilderPool.Borrow()
                                           .AppendLine($"public Type PropertyName")
                                           .AppendLine("{")
                                           .AppendLine($"    get => {assignment.Left};")
                                           .AppendLine()
                                           .AppendLine("    set")
                                           .AppendLine("    {")
                                           .AppendLine($"        if ({Snippet.EqualityCheck(property.Type, "value", assignment.Left.ToString(), semanticModel)})")
                                           .AppendLine("        {")
                                           .AppendLine($"           return;")
                                           .AppendLine("        }")
                                           .AppendLine()
                                           .AppendLine($"        {assignment};")
                                           .AppendLine($"        {Snippet.OnPropertyChanged(invoker, property.Name, underscoreFields)}")
                                           .AppendLine("    }")
                                           .AppendLine("}")
                                           .Return();
                    var template = ParseProperty(code);
                    editor.ReplaceNode(
                        setter,
                        (x, _) =>
                    {
                        var old = (AccessorDeclarationSyntax)x;
                        return(old.WithBody(template.Setter().Body)
                               .WithExpressionBody(null)
                               .WithSemicolonToken(SyntaxFactory.Token(SyntaxKind.None)));
                    });
                    editor.FormatNode(propertyDeclaration);
                }

                if (setter.Body?.Statements.Count == 1 &&
                    IsSimpleAssignmentOnly(propertyDeclaration, out _, out var statement, out assignment, out _))
                {
                    var property = semanticModel.GetDeclaredSymbolSafe(propertyDeclaration, cancellationToken);
                    var code     = StringBuilderPool.Borrow()
                                   .AppendLine($"        if ({Snippet.EqualityCheck(property.Type, "value", assignment.Left.ToString(), semanticModel)})")
                                   .AppendLine("        {")
                                   .AppendLine($"           return;")
                                   .AppendLine("        }")
                                   .AppendLine()
                                   .Return();
                    var ifStatement = SyntaxFactory.ParseStatement(code)
                                      .WithSimplifiedNames()
                                      .WithLeadingElasticLineFeed()
                                      .WithTrailingElasticLineFeed()
                                      .WithAdditionalAnnotations(Formatter.Annotation);
                    editor.InsertBefore(
                        statement,
                        ifStatement);
                    var underscoreFields = CodeStyle.UnderscoreFields(semanticModel);
                    var notifyStatement  = SyntaxFactory
                                           .ParseStatement(
                        Snippet.OnPropertyChanged(invoker, property.Name, underscoreFields))
                                           .WithSimplifiedNames()
                                           .WithLeadingElasticLineFeed()
                                           .WithTrailingElasticLineFeed()
                                           .WithAdditionalAnnotations(Formatter.Annotation);
                    editor.InsertAfter(statement, notifyStatement);
                    editor.FormatNode(propertyDeclaration);
                }
            }
        }