private static TypeDeclarationSyntax GetOrCreateTargetType(SyntaxNode sourceSymbol, SyntaxNode targetNamespace, IFrameworkSet frameworkSet, ClassModel classModel, out TypeDeclarationSyntax originalTargetType)
        {
            TypeDeclarationSyntax targetType = null;

            originalTargetType = null;

            if (targetNamespace != null && sourceSymbol != null)
            {
                var types = TestableItemExtractor.GetTypeDeclarations(targetNamespace);

                var targetClassName = frameworkSet.GetTargetTypeName(classModel, true);
                originalTargetType = targetType = types.FirstOrDefault(x => string.Equals(x.GetClassName(), targetClassName, StringComparison.OrdinalIgnoreCase));

                if (originalTargetType == null)
                {
                    targetClassName    = frameworkSet.GetTargetTypeName(classModel, false);
                    originalTargetType = targetType = types.FirstOrDefault(x => string.Equals(x.GetClassName(), targetClassName, StringComparison.OrdinalIgnoreCase));
                }
            }

            if (targetType == null)
            {
                targetType = new ClassGenerationStrategyFactory(frameworkSet).CreateFor(classModel);
            }
            else
            {
                targetType = EnsureAllConstructorParametersHaveFields(frameworkSet, classModel, targetType);
            }

            return(targetType);
        }
        public ClassDeclarationSyntax Create(ClassModel model)
        {
            if (model == null)
            {
                throw new ArgumentNullException(nameof(model));
            }

            var classDeclaration = SyntaxFactory.ClassDeclaration(_frameworkSet.GetTargetTypeName(model, true));

            model.TargetInstance = model.TypeSyntax;

            classDeclaration = classDeclaration.AddModifiers(SyntaxFactory.Token(SyntaxKind.PublicKeyword));
            if (_frameworkSet.TestFramework.SupportsStaticTestClasses)
            {
                classDeclaration = classDeclaration.AddModifiers(SyntaxFactory.Token(SyntaxKind.StaticKeyword));
            }

            if (!string.IsNullOrWhiteSpace(_frameworkSet.TestFramework.TestClassAttribute))
            {
                var testFixtureAtt = Generate.Attribute(_frameworkSet.TestFramework.TestClassAttribute);
                var list           = SyntaxFactory.AttributeList(SyntaxFactory.SingletonSeparatedList(testFixtureAtt));
                classDeclaration = classDeclaration.AddAttributeLists(list);
            }

            return(classDeclaration);
        }
        public ClassDeclarationSyntax Create(ClassModel model)
        {
            if (model is null)
            {
                throw new ArgumentNullException(nameof(model));
            }

            var targetTypeName   = _frameworkSet.GetTargetTypeName(model, true);
            var classDeclaration = SyntaxFactory.ClassDeclaration(targetTypeName);

            classDeclaration = classDeclaration.AddModifiers(SyntaxFactory.Token(SyntaxKind.PublicKeyword));
            if (!string.IsNullOrWhiteSpace(_frameworkSet.TestFramework.TestClassAttribute))
            {
                var testFixtureAtt = Generate.Attribute(_frameworkSet.TestFramework.TestClassAttribute);
                var list           = SyntaxFactory.AttributeList(SyntaxFactory.SingletonSeparatedList(testFixtureAtt));
                classDeclaration = classDeclaration.AddAttributeLists(list);
            }

            classDeclaration = classDeclaration.AddMembers(GenerateConcreteInheritor(model));

            var variableDeclaration = SyntaxFactory.VariableDeclaration(SyntaxFactory.ParseTypeName("Test" + model.ClassName))
                                      .AddVariables(SyntaxFactory.VariableDeclarator("_testClass"));

            var fieldDeclaration = SyntaxFactory.FieldDeclaration(variableDeclaration)
                                   .AddModifiers(SyntaxFactory.Token(SyntaxKind.PrivateKeyword));

            classDeclaration = classDeclaration.AddMembers(fieldDeclaration);

            var setupMethod = Generate.SetupMethod(model, targetTypeName, _frameworkSet, ref classDeclaration);

            var identifierNameSyntax = SyntaxFactory.IdentifierName("Test" + model.ClassName);

            model.TypeSyntax = identifierNameSyntax;

            var creationExpression = model.GetObjectCreationExpression(_frameworkSet);

            var assignment = SyntaxFactory.AssignmentExpression(
                SyntaxKind.SimpleAssignmentExpression,
                model.TargetInstance,
                creationExpression);

            setupMethod = setupMethod.AddBodyStatements(SyntaxFactory.ExpressionStatement(assignment));

            classDeclaration = classDeclaration.AddMembers(setupMethod);

            return(classDeclaration);
        }
        private static TypeDeclarationSyntax EnsureAllConstructorParametersHaveFields(IFrameworkSet frameworkSet, ClassModel classModel, TypeDeclarationSyntax targetType)
        {
            var setupMethod = frameworkSet.TestFramework.CreateSetupMethod(frameworkSet.GetTargetTypeName(classModel, true));

            BaseMethodDeclarationSyntax foundMethod = null, updatedMethod = null;

            if (setupMethod is MethodDeclarationSyntax methodSyntax)
            {
                updatedMethod = foundMethod = targetType.Members.OfType <MethodDeclarationSyntax>().FirstOrDefault(x => x.Identifier.Text == methodSyntax.Identifier.Text && x.ParameterList.Parameters.Count == 0);
            }
            else if (setupMethod is ConstructorDeclarationSyntax)
            {
                updatedMethod = foundMethod = targetType.Members.OfType <ConstructorDeclarationSyntax>().FirstOrDefault(x => x.ParameterList.Parameters.Count == 0);
            }

            if (foundMethod != null)
            {
                var parametersEmitted = new HashSet <string>();
                var allFields         = new HashSet <string>(StringComparer.OrdinalIgnoreCase);

                var fields = new List <FieldDeclarationSyntax>();
                foreach (var parameterModel in classModel.Constructors.SelectMany(x => x.Parameters))
                {
                    allFields.Add(classModel.GetConstructorParameterFieldName(parameterModel));
                }

                // generate fields for each constructor parameter that doesn't have an existing field
                foreach (var parameterModel in classModel.Constructors.SelectMany(x => x.Parameters))
                {
                    if (!parametersEmitted.Add(parameterModel.Name))
                    {
                        continue;
                    }

                    var fieldName = classModel.GetConstructorParameterFieldName(parameterModel);

                    var fieldExists = targetType.Members.OfType <FieldDeclarationSyntax>().Any(x => x.Declaration.Variables.Any(v => v.Identifier.Text == fieldName));

                    if (!fieldExists)
                    {
                        var variable = SyntaxFactory.VariableDeclaration(parameterModel.TypeInfo.ToTypeSyntax(frameworkSet.Context))
                                       .AddVariables(SyntaxFactory.VariableDeclarator(fieldName));
                        var field = SyntaxFactory.FieldDeclaration(variable)
                                    .AddModifiers(SyntaxFactory.Token(SyntaxKind.PrivateKeyword));

                        fields.Add(field);

                        var defaultExpression = AssignmentValueHelper.GetDefaultAssignmentValue(parameterModel.TypeInfo, classModel.SemanticModel, frameworkSet);

                        var statement = SyntaxFactory.ExpressionStatement(SyntaxFactory.AssignmentExpression(SyntaxKind.SimpleAssignmentExpression, SyntaxFactory.IdentifierName(fieldName), defaultExpression));

                        var body = updatedMethod.Body ?? SyntaxFactory.Block();

                        SyntaxList <StatementSyntax> newStatements;
                        var index = body.Statements.LastIndexOf(x => x.DescendantNodes().OfType <AssignmentExpressionSyntax>().Any(a => a.Left is IdentifierNameSyntax identifierName && allFields.Contains(identifierName.Identifier.Text)));
                        if (index >= 0 && index < body.Statements.Count - 1)
                        {
                            newStatements = body.Statements.Insert(index + 1, statement);
                        }
                        else
                        {
                            newStatements = body.Statements.Add(statement);
                        }

                        updatedMethod = updatedMethod.WithBody(body.WithStatements(newStatements));
                    }
                }

                if (fields.Any())
                {
                    targetType = targetType.ReplaceNode(foundMethod, updatedMethod);
                    var existingField = targetType.Members.OfType <FieldDeclarationSyntax>().LastOrDefault();
                    if (existingField != null)
                    {
                        targetType = targetType.InsertNodesAfter(existingField, fields);
                    }
                    else
                    {
                        targetType = targetType.AddMembers(fields.OfType <MemberDeclarationSyntax>().ToArray());
                    }
                }
            }

            return(targetType);
        }