| File: src\roslyn\src\Workspaces\SharedUtilitiesAndExtensions\Workspace\Core\LanguageServices\InitializeParameter\InitializeParameterHelpersCore.cs | Web Access |
| Project: Microsoft.CodeAnalysis.CodeStyle.Fixes.csproj (Microsoft.CodeAnalysis.CodeStyle.Fixes) |
// Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. using System.Collections.Immutable; using System.Diagnostics.CodeAnalysis; using Microsoft.CodeAnalysis.Diagnostics.Analyzers.NamingStyles; using Microsoft.CodeAnalysis.Operations; using Microsoft.CodeAnalysis.PooledObjects; using Microsoft.CodeAnalysis.Shared.Utilities; namespace Microsoft.CodeAnalysis.InitializeParameter; internal static class InitializeParameterHelpersCore { public static ImmutableArray<(IParameterSymbol parameter, bool before)> GetSiblingParameters(IParameterSymbol parameter) { using var _ = ArrayBuilder<(IParameterSymbol, bool before)>.GetInstance(out var siblings); if (parameter.ContainingSymbol is IMethodSymbol method) { var parameterIndex = method.Parameters.IndexOf(parameter); // look for an existing assignment for a parameter that comes before us. // If we find one, we'll add ourselves after that parameter check. for (var i = parameterIndex - 1; i >= 0; i--) siblings.Add((method.Parameters[i], before: true)); // look for an existing check for a parameter that comes before us. // If we find one, we'll add ourselves after that parameter check. for (var i = parameterIndex + 1; i < method.Parameters.Length; i++) siblings.Add((method.Parameters[i], before: false)); } return siblings.ToImmutableAndClear(); } public static bool IsParameterReference(IOperation? operation, IParameterSymbol parameter) => operation.UnwrapImplicitConversion() is IParameterReferenceOperation parameterReference && parameter.Equals(parameterReference.Parameter); public static bool IsParameterReferenceOrCoalesceOfParameterReference( IOperation? value, IParameterSymbol parameter) { if (IsParameterReference(value, parameter)) { // We already have a member initialized with this parameter like: // this.field = parameter return true; } if (value.UnwrapImplicitConversion() is ICoalesceOperation coalesceExpression && IsParameterReference(coalesceExpression.Value, parameter)) { // We already have a member initialized with this parameter like: // this.field = parameter ?? ... return true; } return false; } public static string GenerateUniqueName(IParameterSymbol parameter, ImmutableArray<string> parameterNameParts, NamingRule rule) { // Determine an appropriate name to call the new field. var containingType = parameter.ContainingType; var baseName = rule.NamingStyle.CreateName(parameterNameParts); // Ensure that the name is unique in the containing type so we // don't stomp on an existing member. var uniqueName = NameGenerator.GenerateUniqueName( baseName, n => containingType.GetMembers(n).IsEmpty); return uniqueName; } public static IOperation? TryFindFieldOrPropertyAssignmentStatement(IParameterSymbol parameter, IBlockOperation? blockStatement) => TryFindFieldOrPropertyAssignmentStatement(parameter, blockStatement, out _); private static IOperation? TryFindFieldOrPropertyAssignmentStatement( IParameterSymbol parameter, IBlockOperation? blockStatement, out ISymbol? fieldOrProperty) { if (blockStatement != null) { var containingType = parameter.ContainingType; foreach (var statement in blockStatement.Operations) { // look for something of the form: "this.s = s" or "this.s = s ?? ..." if (IsFieldOrPropertyAssignment(statement, containingType, out var assignmentExpression, out fieldOrProperty) && IsParameterReferenceOrCoalesceOfParameterReference(assignmentExpression, parameter)) { return statement; } // look inside the form `(this.s, this.t) = (s, t)` if (TryGetPartsOfTupleAssignmentOperation(statement, out var targetTuple, out var valueTuple)) { for (int i = 0, n = targetTuple.Elements.Length; i < n; i++) { var target = targetTuple.Elements[i]; var value = valueTuple.Elements[i]; if (IsFieldOrPropertyReference(target, containingType, out fieldOrProperty) && IsParameterReference(value, parameter)) { return statement; } } } } } fieldOrProperty = null; return null; } public static bool TryGetPartsOfTupleAssignmentOperation( IOperation operation, [NotNullWhen(true)] out ITupleOperation? targetTuple, [NotNullWhen(true)] out ITupleOperation? valueTuple) { if (operation is IExpressionStatementOperation { Operation: IDeconstructionAssignmentOperation { Target: ITupleOperation targetTupleTemp, Value: IConversionOperation { Operand: ITupleOperation valueTupleTemp }, } } && targetTupleTemp.Elements.Length == valueTupleTemp.Elements.Length) { targetTuple = targetTupleTemp; valueTuple = valueTupleTemp; return true; } targetTuple = null; valueTuple = null; return false; } private static bool IsParameterReferenceOrCoalesceOfParameterReference( IAssignmentOperation assignmentExpression, IParameterSymbol parameter) => IsParameterReferenceOrCoalesceOfParameterReference(assignmentExpression.Value, parameter); public static bool IsFieldOrPropertyReference( IOperation? operation, INamedTypeSymbol containingType, [NotNullWhen(true)] out ISymbol? fieldOrProperty) { if (operation is IMemberReferenceOperation memberReference && memberReference.Member.ContainingType.Equals(containingType)) { if (memberReference.Member is IFieldSymbol or IPropertySymbol) { fieldOrProperty = memberReference.Member; return true; } } fieldOrProperty = null; return false; } public static bool IsFieldOrPropertyAssignment(IOperation statement, INamedTypeSymbol containingType, [NotNullWhen(true)] out IAssignmentOperation? assignmentExpression) => IsFieldOrPropertyAssignment(statement, containingType, out assignmentExpression, out _); public static bool IsFieldOrPropertyAssignment( IOperation statement, INamedTypeSymbol containingType, [NotNullWhen(true)] out IAssignmentOperation? assignmentExpression, [NotNullWhen(true)] out ISymbol? fieldOrProperty) { if (statement is IExpressionStatementOperation expressionStatement && expressionStatement.Operation is IAssignmentOperation assignment) { assignmentExpression = assignment; return InitializeParameterHelpersCore.IsFieldOrPropertyReference(assignmentExpression.Target, containingType, out fieldOrProperty); } fieldOrProperty = null; assignmentExpression = null; return false; } }