Example #1
0
        public sealed override async Task ComputeRefactoringsAsync(CodeRefactoringContext context)
        {
            var(document, classDeclarationSyntax) = await context.FindSyntaxForCurrentSpan <ClassDeclarationSyntax>();

            if (document == null || classDeclarationSyntax == null)
            {
                return;
            }

            if (!ClassDeclarationSyntaxAnalysis.IsRecordLike(classDeclarationSyntax))
            {
                return;
            }

            var(atMostOneConstructor, nonTrivialConstructorCandidate) =
                ClassDeclarationSyntaxAnalysis.HasAtMostOneNoneTrivialConstructor(classDeclarationSyntax);

            if (!atMostOneConstructor || nonTrivialConstructorCandidate == null)
            {
                return;
            }

            var properties = ClassDeclarationSyntaxAnalysis.GetPropertyDeclarations(classDeclarationSyntax).ToList();

            if (properties.Count == 0 ||
                properties.Any(PropertyDeclarationSyntaxExtensions.IsStatic))
            {
                return;
            }

            var cancellationToken = context.CancellationToken;
            var semanticModel     = await document.GetSemanticModelAsync(cancellationToken);

            var constructorSymbol = semanticModel.GetDeclaredSymbol(nonTrivialConstructorCandidate);
            var propertySymbols   = properties.Select(p => semanticModel.GetDeclaredSymbol(p, cancellationToken)).ToArray();

            var analyser = new ConstructorPropertyRelationshipAnalyser(
                Array.Empty <IFieldSymbol>(),
                propertySymbols);

            var result = analyser.Analyze(semanticModel, nonTrivialConstructorCandidate);

            var(idxMappings, isExhaustive) = result.GetIndexMapping(propertySymbols, constructorSymbol);
            if (!isExhaustive)
            {
                return;
            }

            context.RegisterRefactoring(
                new DelegateCodeAction(
                    "Generate with methods for parameters",
                    (c) => GenerateWithMethods(document, classDeclarationSyntax, properties, idxMappings, c)));

            return;
        }
Example #2
0
        public sealed override async Task ComputeRefactoringsAsync(CodeRefactoringContext context)
        {
            var(document, classDeclarationSyntax) = await context.FindSyntaxForCurrentSpan <ClassDeclarationSyntax>();

            if (document == null || classDeclarationSyntax == null)
            {
                return;
            }

            if (!ClassDeclarationSyntaxAnalysis.IsRecordLike(classDeclarationSyntax))
            {
                return;
            }

            var(atMostOneConstructor, nonTrivialConstructorCandidate) =
                ClassDeclarationSyntaxAnalysis.HasAtMostOneNoneTrivialConstructor(classDeclarationSyntax);

            if (!atMostOneConstructor)
            {
                return;
            }

            var properties = ClassDeclarationSyntaxAnalysis.GetPropertyDeclarations(classDeclarationSyntax).ToList();

            if (properties.Count == 0 ||
                properties.Any(PropertyDeclarationSyntaxExtensions.IsStatic))
            {
                return;
            }

            context.RegisterRefactoring(
                new DelegateCodeAction(
                    "Generate constructor from parameters",
                    (c) => GenerateConstructor(document, classDeclarationSyntax, properties, nonTrivialConstructorCandidate, c)));

            return;
        }
Example #3
0
        public override async Task ComputeRefactoringsAsync(CodeRefactoringContext context)
        {
            var(document, classDeclarationSyntax) = await context.FindSyntaxForCurrentSpan <ClassDeclarationSyntax>();

            if (document == null || classDeclarationSyntax == null)
            {
                return;
            }

            if (ClassDeclarationSyntaxAnalysis.IsPartial(classDeclarationSyntax) ||
                ClassDeclarationSyntaxAnalysis.IsStatic(classDeclarationSyntax))
            {
                return;
            }

            var(atMostOneNonTrivialConstructor, nonTrivialConstructorCandidate) =
                ClassDeclarationSyntaxAnalysis.HasAtMostOneNoneTrivialConstructor(classDeclarationSyntax);

            if (!atMostOneNonTrivialConstructor)
            {
                return;
            }

            var(_, propertyDeclaration) = await context.FindSyntaxForCurrentSpan <PropertyDeclarationSyntax>();

            var(_, fieldDeclaration) = await context.FindSyntaxForCurrentSpan <FieldDeclarationSyntax>();

            // TODO: Skip properties like string Prop => "something";
            if ((fieldDeclaration == null && propertyDeclaration == null) ||
                (fieldDeclaration != null && fieldDeclaration.IsStatic()) ||
                (propertyDeclaration != null && propertyDeclaration.IsStatic()))
            {
                return;
            }

            var(_, fieldVariableDeclaration) = await context.FindVariableDeclaratorForCurrentSpan();

            if (fieldDeclaration != null && fieldVariableDeclaration == null)
            {
                return;
            }

            switch (nonTrivialConstructorCandidate)
            {
            case ConstructorDeclarationSyntax candidate:
            {
                var cancellationToken = context.CancellationToken;
                var semanticModel     = await document.GetSemanticModelAsync(cancellationToken);

                HandleCandidate(semanticModel, candidate, propertyDeclaration, fieldDeclaration, fieldVariableDeclaration);
            }
            break;

            case null:
            {
                var trivialConstructor = ClassDeclarationSyntaxAnalysis.GetConstructors(classDeclarationSyntax)?.FirstOrDefault();
                if (trivialConstructor != null)
                {
                    var cancellationToken = context.CancellationToken;
                    var semanticModel     = await document.GetSemanticModelAsync(cancellationToken);

                    HandleCandidate(semanticModel, trivialConstructor, propertyDeclaration, fieldDeclaration, fieldVariableDeclaration);
                }
                else
                {
                    // TODO: register add constructor refactoring
                }
            }

            break;
            }

            void HandleCandidate(
                SemanticModel model,
                ConstructorDeclarationSyntax candidate,
                PropertyDeclarationSyntax pDeclaration,
                FieldDeclarationSyntax fDeclaration,
                VariableDeclaratorSyntax variableDeclarator)
            {
                bool    isProp            = pDeclaration != null;
                var     constructorSymbol = model.GetDeclaredSymbol(candidate) as IMethodSymbol;
                ISymbol memberSymbol      = isProp ?
                                            model.GetDeclaredSymbol(pDeclaration)
                    :  model.GetDeclaredSymbol(variableDeclarator);

                if (constructorSymbol == null || memberSymbol == null)
                {
                    return;
                }

                var analyser = new ConstructorPropertyRelationshipAnalyser(
                    isProp ? Array.Empty <IFieldSymbol>() : new[] { memberSymbol as IFieldSymbol },
                    isProp ? new[] { memberSymbol as IPropertySymbol } : Array.Empty <IPropertySymbol>());

                var result             = analyser.Analyze(model, candidate);
                var assignmentResult   = result.GetResult(memberSymbol);
                AnalysedDeclaration ad = isProp ?
                                         (AnalysedDeclaration) new PropertyDeclaration(memberSymbol as IPropertySymbol, pDeclaration)
                    : new FieldDeclaration(memberSymbol as IFieldSymbol, fDeclaration, variableDeclarator);

                switch (assignmentResult)
                {
                case AssignmentExpressionAnalyserResult r:
                    // register remove as assignment exists
                    context.RegisterRefactoring(
                        new DelegateCodeAction(
                            $"Remove {ad.Identifier.ValueText}",
                            (c) => RefactoringActions.RemoveParameter(
                                document,
                                classDeclarationSyntax,
                                ad,
                                candidate,
                                c)));
                    break;

                case EmptyAssignmentAnalyserResult _:
                    // register add to constructor
                    context.RegisterRefactoring(
                        new DelegateCodeAction(
                            $"Add {ad.Identifier.ValueText} to constructor",
                            (c) => RefactoringActions.AddParameterToConstructor(
                                document,
                                classDeclarationSyntax,
                                ad,
                                constructorSymbol,
                                candidate,
                                c)));
                    break;

                case MultipleAssignments _:
                case ParsingError _:
                default:
                    // Something went wrong so it might be better to do nothing.
                    break;
                }
            }
        }