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.
EvaluateManagedBackingFieldsAnalayzer.cs
Go to the documentation of this file.
1using Microsoft.CodeAnalysis;
2using Microsoft.CodeAnalysis.CSharp;
3using Microsoft.CodeAnalysis.CSharp.Syntax;
4using Microsoft.CodeAnalysis.Diagnostics;
5using System;
6using System.Collections.Immutable;
7using System.Linq;
9
10namespace Csla.Analyzers
11{
12 [DiagnosticAnalyzer(LanguageNames.CSharp)]
14 : DiagnosticAnalyzer
15 {
16 private static readonly DiagnosticDescriptor mustBePublicStaticAndReadonlyRule =
17 new DiagnosticDescriptor(
18 Constants.AnalyzerIdentifiers.EvaluateManagedBackingFields,
19 EvaluateManagedBackingFieldsAnalayzerConstants.Title,
20 EvaluateManagedBackingFieldsAnalayzerConstants.Message,
21 Constants.Categories.Usage, DiagnosticSeverity.Error, true,
22 helpLinkUri: HelpUrlBuilder.Build(
23 Constants.AnalyzerIdentifiers.EvaluateManagedBackingFields, nameof(EvaluateManagedBackingFieldsAnalayzer)));
24
25 public override ImmutableArray<DiagnosticDescriptor> SupportedDiagnostics =>
26 ImmutableArray.Create(mustBePublicStaticAndReadonlyRule);
27
28 public override void Initialize(AnalysisContext context)
29 {
30 context.ConfigureGeneratedCodeAnalysis(GeneratedCodeAnalysisFlags.Analyze | GeneratedCodeAnalysisFlags.ReportDiagnostics);
31 context.EnableConcurrentExecution();
32 context.RegisterSyntaxNodeAction(AnalyzeFieldDeclaration, SyntaxKind.FieldDeclaration);
33 }
34
35 private static void AnalyzeFieldDeclaration(SyntaxNodeAnalysisContext context)
36 {
37 var fieldNode = (FieldDeclarationSyntax)context.Node;
38
39 if (!fieldNode.ContainsDiagnostics)
40 {
41 foreach (var variable in fieldNode.Declaration.Variables)
42 {
43 var fieldSymbol = context.SemanticModel.GetDeclaredSymbol(variable) as IFieldSymbol;
44 var classSymbol = fieldSymbol?.ContainingType;
45
46 context.CancellationToken.ThrowIfCancellationRequested();
47
48 if (fieldSymbol != null && classSymbol != null && classSymbol.IsStereotype())
49 {
50 if (fieldSymbol.Type.IsIPropertyInfo())
51 {
52 foreach (var classMember in classSymbol.GetMembers())
53 {
54 if (classMember.Kind == SymbolKind.Property)
55 {
56 var classProperty = classMember as IPropertySymbol;
57
58 if (!classProperty.IsIndexer)
59 {
60 if (DetermineIfPropertyUsesField(context, fieldSymbol, classProperty))
61 {
62 context.CancellationToken.ThrowIfCancellationRequested();
63
64 CheckForDiagnostics(context, fieldNode, fieldSymbol);
65 break;
66 }
67 }
68 }
69 }
70 }
71 }
72 }
73 }
74 }
75
76 private static void CheckForDiagnostics(SyntaxNodeAnalysisContext context, FieldDeclarationSyntax fieldNode, IFieldSymbol fieldSymbol)
77 {
78 var isStatic = fieldSymbol.IsStatic;
79 var isPublic = fieldSymbol.DeclaredAccessibility.HasFlag(Accessibility.Public);
80 var isReadOnly = fieldSymbol.IsReadOnly;
81
82 if (!isStatic || !isPublic || !isReadOnly)
83 {
84 context.ReportDiagnostic(Diagnostic.Create(
85 mustBePublicStaticAndReadonlyRule, fieldNode.GetLocation()));
86 }
87 }
88
89 private static bool DetermineIfPropertyUsesField(SyntaxNodeAnalysisContext context,
90 IFieldSymbol fieldSymbol, IPropertySymbol classProperty,
91 Func<PropertyDeclarationSyntax, SyntaxNode> propertyBody)
92 {
93 var root = context.Node.SyntaxTree.GetRoot();
94 var rootSpan = root.FullSpan;
95 var classPropertyLocationSpan = classProperty.Locations[0].SourceSpan;
96
97 if (rootSpan.Contains(classPropertyLocationSpan))
98 {
99 if (root.FindNode(classPropertyLocationSpan) is PropertyDeclarationSyntax propertyNode)
100 {
101 var getter = propertyBody(propertyNode);
102
103 if (new EvaluateManagedBackingFieldsWalker(getter, context.SemanticModel, fieldSymbol).UsesField)
104 {
105 return true;
106 }
107 }
108 }
109
110 return false;
111 }
112
113 private static bool DetermineIfPropertyUsesField(SyntaxNodeAnalysisContext context,
114 IFieldSymbol fieldSymbol, IPropertySymbol classProperty)
115 {
116 if (classProperty.GetMethod != null)
117 {
118 return DetermineIfPropertyUsesField(
119 context, fieldSymbol, classProperty,
120 propertyNode => propertyNode.ExpressionBody as SyntaxNode ??
121 propertyNode.AccessorList.Accessors.Single(
122 _ => _.IsKind(SyntaxKind.GetAccessorDeclaration)));
123 }
124
125 if (classProperty.SetMethod != null)
126 {
127 return DetermineIfPropertyUsesField(
128 context, fieldSymbol, classProperty,
129 propertyNode => propertyNode.AccessorList.Accessors.Single(
130 _ => _.IsKind(SyntaxKind.SetAccessorDeclaration)));
131 }
132
133 return false;
134 }
135 }
136}
override ImmutableArray< DiagnosticDescriptor > SupportedDiagnostics