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))); } } } }
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); } }