private static void HandleConstructor(SyntaxNodeAnalysisContext context)
        {
            if (context.IsExcludedFromAnalysis())
            {
                return;
            }

            if (context.Node is ConstructorDeclarationSyntax constructorDeclaration &&
                context.ContainingSymbol is IMethodSymbol ctor)
            {
                if (!ctor.IsStatic &&
                    ctor.DeclaredAccessibility == Accessibility.Private)
                {
                    return;
                }

                using (var pooled = CtorWalker.Borrow(constructorDeclaration, context.SemanticModel, context.CancellationToken))
                {
                    if (pooled.Unassigned.Any())
                    {
                        context.ReportDiagnostic(
                            Diagnostic.Create(
                                Descriptor,
                                constructorDeclaration.Identifier.GetLocation(),
                                string.Join(Environment.NewLine, pooled.Unassigned)));
                    }
                }
            }
        }
Esempio n. 2
0
        private static void HandleConstructor(SyntaxNodeAnalysisContext context)
        {
            if (context.IsExcludedFromAnalysis())
            {
                return;
            }

            var constructorDeclarationSyntax = (ConstructorDeclarationSyntax)context.Node;
            var ctor = (IMethodSymbol)context.ContainingSymbol;

            if (!ctor.IsStatic && ctor.DeclaredAccessibility == Accessibility.Private)
            {
                return;
            }

            using (var pooled = CtorWalker.Create(constructorDeclarationSyntax, context.SemanticModel, context.CancellationToken))
            {
                if (pooled.Item.Unassigned.Any())
                {
                    context.ReportDiagnostic(Diagnostic.Create(Descriptor, constructorDeclarationSyntax.GetLocation(), string.Join(", ", pooled.Item.Unassigned)));
                }
            }
        }
        private static void Handle(SyntaxNodeAnalysisContext context)
        {
            if (!context.IsExcludedFromAnalysis() &&
                context.Node is ConstructorDeclarationSyntax constructorDeclaration)
            {
                using (var walker = CtorWalker.Borrow(constructorDeclaration, context.SemanticModel, context.CancellationToken))
                {
                    if (constructorDeclaration.ParameterList is ParameterListSyntax parameterList &&
                        parameterList.Parameters.Count > 0)
                    {
                        foreach (var parameter in parameterList.Parameters)
                        {
                            if (ShouldRename(parameter, walker, context, out var name))
                            {
                                var properties = ImmutableDictionary.CreateRange(new[] { new KeyValuePair <string, string>("Name", name), });
                                context.ReportDiagnostic(Diagnostic.Create(GU0003CtorParameterNamesShouldMatch.Descriptor, parameter.Identifier.GetLocation(), properties));
                            }
                        }

                        foreach (var assignment in walker.Assignments)
                        {
                            if (constructorDeclaration.Contains(assignment) &&
                                TryGetIdentifier(assignment.Left, out var left))
                            {
                                if (TryGetIdentifier(assignment.Right, out var right) &&
                                    parameterList.Parameters.TryFirst(x => x.Identifier.ValueText == right.Identifier.ValueText, out var parameter) &&
                                    !parameter.Modifiers.Any(SyntaxKind.ParamsKeyword) &&
                                    walker.Assignments.TrySingle(x => x.Right is IdentifierNameSyntax id && id.Identifier.ValueText == parameter.Identifier.ValueText, out _) &&
                                    context.SemanticModel.TryGetSymbol(left, context.CancellationToken, out ISymbol leftSymbol))
                                {
                                    foreach (var argument in walker.Arguments)
                                    {
                                        if (argument.Parent is ArgumentListSyntax al &&
                                            al.Parent is InvocationExpressionSyntax invocation &&
                                            invocation.TryGetMethodName(out var methodName) &&
                                            methodName == "nameof")
                                        {
                                            continue;
                                        }

                                        if (ShouldUseParameter(context, leftSymbol, argument.Expression))
                                        {
                                            var properties = ImmutableDictionary.CreateRange(new[] { new KeyValuePair <string, string>("Name", parameter.Identifier.ValueText), });
                                            context.ReportDiagnostic(Diagnostic.Create(GU0014PreferParameter.Descriptor, argument.Expression.GetLocation(), properties));
                                        }
                                    }

                                    foreach (var invocation in walker.Invocations)
                                    {
                                        if (ShouldUseParameter(context, leftSymbol, invocation.Expression))
                                        {
                                            var properties = ImmutableDictionary.CreateRange(new[] { new KeyValuePair <string, string>("Name", parameter.Identifier.ValueText), });
                                            context.ReportDiagnostic(Diagnostic.Create(GU0014PreferParameter.Descriptor, invocation.Expression.GetLocation(), properties));
                                        }
                                    }

                                    foreach (var memberAccess in walker.MemberAccesses)
                                    {
                                        if (ShouldUseParameter(context, leftSymbol, memberAccess.Expression))
                                        {
                                            var properties = ImmutableDictionary.CreateRange(new[] { new KeyValuePair <string, string>("Name", parameter.Identifier.ValueText), });
                                            context.ReportDiagnostic(Diagnostic.Create(GU0014PreferParameter.Descriptor, memberAccess.Expression.GetLocation(), properties));
                                        }
                                    }

                                    foreach (var conditionalAccess in walker.ConditionalAccesses)
                                    {
                                        if (ShouldUseParameter(context, leftSymbol, conditionalAccess.Expression))
                                        {
                                            var properties = ImmutableDictionary.CreateRange(new[] { new KeyValuePair <string, string>("Name", parameter.Identifier.ValueText), });
                                            context.ReportDiagnostic(Diagnostic.Create(GU0014PreferParameter.Descriptor, conditionalAccess.Expression.GetLocation(), properties));
                                        }
                                    }

                                    foreach (var binaryExpression in walker.BinaryExpressionSyntaxes)
                                    {
                                        if (ShouldUseParameter(context, leftSymbol, binaryExpression.Left))
                                        {
                                            var properties = ImmutableDictionary.CreateRange(new[] { new KeyValuePair <string, string>("Name", parameter.Identifier.ValueText), });
                                            context.ReportDiagnostic(Diagnostic.Create(GU0014PreferParameter.Descriptor, binaryExpression.Left.GetLocation(), properties));
                                        }

                                        if (ShouldUseParameter(context, leftSymbol, binaryExpression.Right))
                                        {
                                            var properties = ImmutableDictionary.CreateRange(new[] { new KeyValuePair <string, string>("Name", parameter.Identifier.ValueText), });
                                            context.ReportDiagnostic(Diagnostic.Create(GU0014PreferParameter.Descriptor, binaryExpression.Right.GetLocation(), properties));
                                        }
                                    }
                                }
                            }
                        }
                    }

                    if (walker.Unassigned.Count > 0)
                    {
                        context.ReportDiagnostic(Diagnostic.Create(GU0004AssignAllReadOnlyMembers.Descriptor, constructorDeclaration.Identifier.GetLocation(), string.Join(Environment.NewLine, walker.Unassigned)));
                    }
                }
            }
        }
        private static bool ShouldRename(ParameterSyntax parameter, CtorWalker walker, SyntaxNodeAnalysisContext context, out string name)
        {
            name = null;
            if (parameter.Parent is ParameterListSyntax parameterList &&
                parameterList.Parent is ConstructorDeclarationSyntax constructorDeclaration)
            {
                foreach (var assignment in walker.Assignments)
                {
                    if (constructorDeclaration.Contains(assignment) &&
                        assignment.Right is IdentifierNameSyntax right &&
                        right.Identifier.ValueText == parameter.Identifier.ValueText &&
                        TryGetIdentifier(assignment.Left, out var left))
                    {
                        if (IsMatch(left, parameter, out var newName))
                        {
                            return(false);
                        }

                        if (name != null &&
                            name != newName)
                        {
                            return(false);
                        }

                        name = newName;
                    }
                }

                if (name != null)
                {
                    return(true);
                }

                if (constructorDeclaration.Initializer is ConstructorInitializerSyntax initializer &&
                    initializer.ArgumentList is ArgumentListSyntax argumentList &&
                    argumentList.Arguments.TrySingle(syntax => IsParameter(syntax), out var argument) &&
                    context.SemanticModel.GetSymbolSafe(initializer, context.CancellationToken) is IMethodSymbol chained &&
                    chained.TryFindParameter(argument, out var parameterSymbol) &&
                    parameterSymbol.IsParams == parameter.Modifiers.Any(SyntaxKind.ParamKeyword) &&
                    parameterSymbol.Name != parameter.Identifier.ValueText &&
                    !char.IsDigit(parameterSymbol.Name[parameterSymbol.Name.Length - 1]))
                {
                    name = parameterSymbol.Name;
                    return(true);
                }
            }

            return(false);

            bool IsMatch(IdentifierNameSyntax left, ParameterSyntax right, out string newName)
            {
                newName = null;
                if (Equals(left.Identifier.ValueText, right.Identifier.ValueText))
                {
                    return(true);
                }

                newName = left.Identifier.ValueText;
                newName = IsAllCaps(newName)
                    ? newName.ToLowerInvariant()
                    : FirstCharLowercase(newName.TrimStart('_'));

                return(false);

                bool Equals(string memberName, string parameterName)
                {
                    if (memberName.StartsWith("_"))
                    {
                        if (parameterName.Length != memberName.Length - 1)
                        {
                            return(false);
                        }

                        for (var i = 0; i < parameterName.Length; i++)
                        {
                            if (parameterName[i] != memberName[i + 1])
                            {
                                return(false);
                            }
                        }

                        return(true);
                    }

                    return(string.Equals(memberName, parameterName, StringComparison.OrdinalIgnoreCase));
                }

                bool IsAllCaps(string text)
                {
                    foreach (var c in text)
                    {
                        if (char.IsLetter(c) && char.IsLower(c))
                        {
                            return(false);
                        }
                    }

                    return(true);
                }

                string FirstCharLowercase(string text)
                {
                    if (char.IsLower(text[0]))
                    {
                        return(text);
                    }

                    var charArray = text.ToCharArray();

                    charArray[0] = char.ToLower(charArray[0]);
                    return(new string(charArray));
                }
            }

            bool IsParameter(ArgumentSyntax argument)
            {
                return(argument.Expression is IdentifierNameSyntax identifierName &&
                       identifierName.Identifier.ValueText == parameter.Identifier.ValueText);
            }
        }