private static Task <Document> RefactorAsync( Document document, RecordDeclarationSyntax recordDeclaration, CancellationToken cancellationToken = default) { ParameterListSyntax parameterList = recordDeclaration.ParameterList; BaseListSyntax baseList = recordDeclaration.BaseList; SeparatedSyntaxList <ParameterSyntax> parameters = parameterList.Parameters; var identifiersMap = new Dictionary <string, SyntaxToken>(); var statements = new List <StatementSyntax>(); var properties = new List <PropertyDeclarationSyntax>(); var allAttributeLists = new List <AttributeListSyntax>(); var baseType = baseList? .Types .FirstOrDefault(f => f.IsKind(SyntaxKind.PrimaryConstructorBaseType)) as PrimaryConstructorBaseTypeSyntax; ImmutableHashSet <string> basePropertyNames = ImmutableHashSet <string> .Empty; if (baseType != null) { basePropertyNames = baseType .ArgumentList? .Arguments .Select(f => f.ToString()) .ToImmutableHashSet(); } bool isWritable = !recordDeclaration.Modifiers.Contains(SyntaxKind.ReadOnlyKeyword) && recordDeclaration.ClassOrStructKeyword.IsKind(SyntaxKind.StructKeyword); foreach (ParameterSyntax parameter in parameters) { SyntaxToken identifier = parameter.Identifier; string identifierText = identifier.ValueText; SyntaxToken parameterIdentifier = Identifier(StringUtility.FirstCharToLower(identifierText)); SyntaxToken propertyIdentifier = Identifier(StringUtility.FirstCharToUpper(identifierText)); identifiersMap.Add(identifier.ValueText, parameterIdentifier); IEnumerable <AttributeListSyntax> attributeLists = parameter.AttributeLists.Where(f => f.Target?.Identifier.IsKind(SyntaxKind.PropertyKeyword) == true); allAttributeLists.AddRange(attributeLists); statements.Add(SimpleAssignmentStatement( IdentifierName(propertyIdentifier).QualifyWithThis(), IdentifierName(parameterIdentifier.WithTriviaFrom(identifier)))); if (!basePropertyNames.Contains(identifierText)) { properties.Add(PropertyDeclaration( attributeLists.Select(f => f.WithTarget(null)).ToSyntaxList(), Modifiers.Public(), parameter.Type, default(ExplicitInterfaceSpecifierSyntax), propertyIdentifier, AccessorList( AutoGetAccessorDeclaration(), (isWritable) ? AutoSetAccessorDeclaration() : AutoInitAccessorDeclaration() ))); } } ParameterListSyntax newParameterList = parameterList.RemoveNodes( allAttributeLists, SyntaxRemoveOptions.KeepLeadingTrivia | SyntaxRemoveOptions.KeepUnbalancedDirectives); newParameterList = newParameterList.ReplaceTokens( newParameterList.Parameters.Select(parameter => parameter.Identifier), (identifier, _) => identifiersMap[identifier.ValueText]); ParameterSyntax firstParameter = parameterList.Parameters[0]; if (firstParameter.GetLeadingTrivia().SingleOrDefault(shouldThrow: false).IsKind(SyntaxKind.WhitespaceTrivia)) { SyntaxTriviaList newIndentation = SyntaxTriviaAnalysis.GetIncreasedIndentationTriviaList(firstParameter, cancellationToken); newParameterList = newParameterList.ReplaceNodes( newParameterList.Parameters, (parameter, _) => { return((parameter.GetLeadingTrivia().SingleOrDefault().IsKind(SyntaxKind.WhitespaceTrivia)) ? parameter.WithLeadingTrivia(newIndentation) : parameter); }); } ConstructorDeclarationSyntax constructor = ConstructorDeclaration( Modifiers.Public(), recordDeclaration.Identifier.WithoutTrivia(), newParameterList, Block(statements)); RecordDeclarationSyntax newRecord = recordDeclaration .WithIdentifier(recordDeclaration.Identifier.WithTrailingTrivia(recordDeclaration.ParameterList.GetTrailingTrivia())) .WithParameterList(null) .WithSemicolonToken(default);
public static ParameterListSyntax WithoutAttributes(this ParameterListSyntax parameterList) { var methodParameterAttributes = parameterList.Parameters.SelectMany(p => p.AttributeLists); return(parameterList.RemoveNodes(methodParameterAttributes, SyntaxRemoveOptions.KeepNoTrivia)); }