Skip to content

Instantly share code, notes, and snippets.

Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save Novakov/bf6e521506a4511e3401 to your computer and use it in GitHub Desktop.
Save Novakov/bf6e521506a4511e3401 to your computer and use it in GitHub Desktop.
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.CSharp;
using Microsoft.CodeAnalysis.CSharp.Syntax;
using Microsoft.CodeAnalysis.CodeRefactorings;
using Microsoft.CodeAnalysis.Formatting;
namespace RefactoringEssentials.CSharp.CodeRefactorings
{
[ExportCodeRefactoringProvider(LanguageNames.CSharp, Name = "Initialize field from constructor parameter")]
public class InitializeFieldFromConstructorParameterCodeRefactoringProvider : CodeRefactoringProvider
{
public override async Task ComputeRefactoringsAsync(CodeRefactoringContext context)
{
var document = context.Document;
if (document.Project.Solution.Workspace.Kind == WorkspaceKind.MiscellaneousFiles)
return;
var span = context.Span;
if (!span.IsEmpty)
return;
var cancellationToken = context.CancellationToken;
if (cancellationToken.IsCancellationRequested)
return;
var model = await document.GetSemanticModelAsync(cancellationToken).ConfigureAwait(false);
if (model.IsFromGeneratedCode(cancellationToken))
return;
var root = await model.SyntaxTree.GetRootAsync(cancellationToken).ConfigureAwait(false);
var token = root.FindToken(span.Start);
var parameter = token.Parent as ParameterSyntax;
if (parameter != null)
{
var ctor = parameter.Parent.Parent as ConstructorDeclarationSyntax;
if (ctor == null)
return;
context.RegisterRefactoring(
CodeActionFactory.Create(
parameter.Span,
DiagnosticSeverity.Info,
GettextCatalog.GetString("Initialize field from parameter"),
document.WithSyntaxRoot(Refactor(root, parameter, ctor))
));
}
}
private static SyntaxNode Refactor(SyntaxNode root, ParameterSyntax parameter, ConstructorDeclarationSyntax ctor)
{
var newField = SyntaxFactory.FieldDeclaration(
SyntaxFactory.VariableDeclaration(
parameter.Type,
SyntaxFactory.SingletonSeparatedList<VariableDeclaratorSyntax>(SyntaxFactory.VariableDeclarator(parameter.Identifier)))
).WithModifiers(SyntaxFactory.TokenList(SyntaxFactory.Token(SyntaxKind.ReadOnlyKeyword)))
.WithAdditionalAnnotations(Formatter.Annotation);
var assignmentStatement = SyntaxFactory.ExpressionStatement(
SyntaxFactory.AssignmentExpression(
SyntaxKind.SimpleAssignmentExpression,
SyntaxFactory.MemberAccessExpression(SyntaxKind.SimpleMemberAccessExpression, SyntaxFactory.ThisExpression(), SyntaxFactory.IdentifierName(parameter.Identifier)),
SyntaxFactory.IdentifierName(parameter.Identifier)
)
).WithAdditionalAnnotations(Formatter.Annotation);
var trackedRoot = root.TrackNodes(ctor);
var newRoot = trackedRoot.InsertNodesBefore(trackedRoot.GetCurrentNode(ctor), new List<SyntaxNode>() {
newField
});
newRoot = newRoot.ReplaceNode(newRoot.GetCurrentNode(ctor), ctor.WithBody(
ctor.Body.WithStatements(SyntaxFactory.List<StatementSyntax>(new[] { assignmentStatement }.Concat(ctor.Body.Statements)))
));
return newRoot;
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment