CSLA.NET 6.0.0
CSLA .NET is a software development framework that helps you build a reusable, maintainable object-oriented business layer for your app.
CheckConstructorsAnalyzerPublicConstructorCodeFix.cs
Go to the documentation of this file.
1using System.Collections.Immutable;
2using System.Composition;
3using System.Linq;
4using System.Threading.Tasks;
5using Microsoft.CodeAnalysis;
6using Microsoft.CodeAnalysis.CodeFixes;
7using Microsoft.CodeAnalysis.CSharp.Syntax;
8using Microsoft.CodeAnalysis.CSharp;
9using Microsoft.CodeAnalysis.CodeActions;
10using Microsoft.CodeAnalysis.Formatting;
11using Microsoft.CodeAnalysis.Editing;
12
13namespace Csla.Analyzers
14{
15 [ExportCodeFixProvider(LanguageNames.CSharp)]
16 [Shared]
18 : CodeFixProvider
19 {
20 public override ImmutableArray<string> FixableDiagnosticIds =>
21 ImmutableArray.Create(Constants.AnalyzerIdentifiers.PublicNoArgumentConstructorIsMissing);
22
23 public sealed override FixAllProvider GetFixAllProvider() => WellKnownFixAllProviders.BatchFixer;
24
25 public override async Task RegisterCodeFixesAsync(CodeFixContext context)
26 {
27 var root = await context.Document.GetSyntaxRootAsync(context.CancellationToken).ConfigureAwait(false);
28
29 context.CancellationToken.ThrowIfCancellationRequested();
30
31 var diagnostic = context.Diagnostics.First();
32 var classNode = root.FindNode(diagnostic.Location.SourceSpan) as ClassDeclarationSyntax;
33
34 context.CancellationToken.ThrowIfCancellationRequested();
35
36 var hasNonPublicNoArgumentConstructor = bool.Parse(
37 diagnostic.Properties[PublicNoArgumentConstructorIsMissingConstants.HasNonPublicNoArgumentConstructor]);
38
39 if (hasNonPublicNoArgumentConstructor)
40 {
41 if (context.Document.SupportsSemanticModel)
42 {
43 var model = await context.Document.GetSemanticModelAsync(context.CancellationToken).ConfigureAwait(false);
44 AddCodeFixWithUpdatingNonPublicConstructor(
45 context, root, diagnostic, classNode, model);
46 }
47 }
48 else
49 {
50 AddCodeFixWithNewPublicConstructor(
51 context, root, diagnostic, classNode);
52 }
53 }
54
55 private static void AddCodeFixWithNewPublicConstructor(CodeFixContext context, SyntaxNode root,
56 Diagnostic diagnostic, ClassDeclarationSyntax classNode)
57 {
58 // Generated from http://roslynquoter.azurewebsites.net/
59 var constructor = SyntaxFactory.ConstructorDeclaration(classNode.Identifier)
60 .WithModifiers(
61 SyntaxFactory.TokenList(
62 SyntaxFactory.Token(SyntaxKind.PublicKeyword)))
63 .WithParameterList(SyntaxFactory.ParameterList()
64 .WithOpenParenToken(
65 SyntaxFactory.Token(SyntaxKind.OpenParenToken))
66 .WithCloseParenToken(
67 SyntaxFactory.Token(
68 SyntaxKind.CloseParenToken)))
69 .WithBody(SyntaxFactory.Block()
70 .WithOpenBraceToken(
71 SyntaxFactory.Token(
72 SyntaxKind.OpenBraceToken))
73 .WithCloseBraceToken(
74 SyntaxFactory.Token(
75 SyntaxKind.CloseBraceToken))).NormalizeWhitespace().WithAdditionalAnnotations(Formatter.Annotation);
76 var newClassNode = classNode.AddMembers(constructor);
77 var newRoot = root.ReplaceNode(classNode, newClassNode);
78
79 context.RegisterCodeFix(
80 CodeAction.Create(
81 CheckConstructorsAnalyzerPublicConstructorCodeFixConstants.AddPublicConstructorDescription,
82 _ => Task.FromResult(context.Document.WithSyntaxRoot(newRoot)),
83 CheckConstructorsAnalyzerPublicConstructorCodeFixConstants.AddPublicConstructorDescription), diagnostic);
84 }
85
86 private static void AddCodeFixWithUpdatingNonPublicConstructor(CodeFixContext context, SyntaxNode root,
87 Diagnostic diagnostic, ClassDeclarationSyntax classNode, SemanticModel model)
88 {
89 var publicModifier = SyntaxFactory.Token(SyntaxKind.PublicKeyword);
90 var classSymbol = model.GetDeclaredSymbol(classNode);
91
92 if (classSymbol != null)
93 {
94 var constructorSymbol = classSymbol.Constructors
95 .Single(_ => _.Parameters.Count() == 0 &&
96 !_.DeclaredAccessibility.HasFlag(Accessibility.Public));
97
98 var constructor = constructorSymbol.DeclaringSyntaxReferences[0].GetSyntax(context.CancellationToken);
99
100 var newConstructor = constructor;
101
102 var generator = SyntaxGenerator.GetGenerator(context.Document);
103 newConstructor = generator.WithAccessibility(newConstructor, Accessibility.Public);
104
105 var newRoot = root.ReplaceNode(constructor, newConstructor);
106
107 context.RegisterCodeFix(
108 CodeAction.Create(
109 CheckConstructorsAnalyzerPublicConstructorCodeFixConstants.UpdateNonPublicConstructorToPublicDescription,
110 _ => Task.FromResult(context.Document.WithSyntaxRoot(newRoot)),
111 CheckConstructorsAnalyzerPublicConstructorCodeFixConstants.UpdateNonPublicConstructorToPublicDescription), diagnostic);
112 }
113 }
114 }
115}