6using System.Collections.Immutable;
12 [DiagnosticAnalyzer(LanguageNames.CSharp)]
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(
26 ImmutableArray.Create(mustBePublicStaticAndReadonlyRule);
30 context.ConfigureGeneratedCodeAnalysis(GeneratedCodeAnalysisFlags.Analyze | GeneratedCodeAnalysisFlags.ReportDiagnostics);
31 context.EnableConcurrentExecution();
32 context.RegisterSyntaxNodeAction(AnalyzeFieldDeclaration, SyntaxKind.FieldDeclaration);
35 private static void AnalyzeFieldDeclaration(SyntaxNodeAnalysisContext context)
37 var fieldNode = (FieldDeclarationSyntax)context.Node;
39 if (!fieldNode.ContainsDiagnostics)
41 foreach (var variable
in fieldNode.Declaration.Variables)
43 var fieldSymbol = context.SemanticModel.GetDeclaredSymbol(variable) as IFieldSymbol;
44 var classSymbol = fieldSymbol?.ContainingType;
46 context.CancellationToken.ThrowIfCancellationRequested();
48 if (fieldSymbol !=
null && classSymbol !=
null && classSymbol.IsStereotype())
50 if (fieldSymbol.Type.IsIPropertyInfo())
52 foreach (var classMember
in classSymbol.GetMembers())
54 if (classMember.Kind == SymbolKind.Property)
56 var classProperty = classMember as IPropertySymbol;
58 if (!classProperty.IsIndexer)
60 if (DetermineIfPropertyUsesField(context, fieldSymbol, classProperty))
62 context.CancellationToken.ThrowIfCancellationRequested();
64 CheckForDiagnostics(context, fieldNode, fieldSymbol);
76 private static void CheckForDiagnostics(SyntaxNodeAnalysisContext context, FieldDeclarationSyntax fieldNode, IFieldSymbol fieldSymbol)
78 var isStatic = fieldSymbol.IsStatic;
79 var isPublic = fieldSymbol.DeclaredAccessibility.HasFlag(Accessibility.Public);
80 var isReadOnly = fieldSymbol.IsReadOnly;
82 if (!isStatic || !isPublic || !isReadOnly)
84 context.ReportDiagnostic(Diagnostic.Create(
85 mustBePublicStaticAndReadonlyRule, fieldNode.GetLocation()));
89 private static bool DetermineIfPropertyUsesField(SyntaxNodeAnalysisContext context,
90 IFieldSymbol fieldSymbol, IPropertySymbol classProperty,
91 Func<PropertyDeclarationSyntax, SyntaxNode> propertyBody)
93 var root = context.Node.SyntaxTree.GetRoot();
94 var rootSpan = root.FullSpan;
95 var classPropertyLocationSpan = classProperty.Locations[0].SourceSpan;
97 if (rootSpan.Contains(classPropertyLocationSpan))
99 if (root.FindNode(classPropertyLocationSpan) is PropertyDeclarationSyntax propertyNode)
101 var getter = propertyBody(propertyNode);
103 if (
new EvaluateManagedBackingFieldsWalker(getter, context.SemanticModel, fieldSymbol).UsesField)
113 private static bool DetermineIfPropertyUsesField(SyntaxNodeAnalysisContext context,
114 IFieldSymbol fieldSymbol, IPropertySymbol classProperty)
116 if (classProperty.GetMethod !=
null)
118 return DetermineIfPropertyUsesField(
119 context, fieldSymbol, classProperty,
120 propertyNode => propertyNode.ExpressionBody as SyntaxNode ??
121 propertyNode.AccessorList.Accessors.Single(
122 _ => _.IsKind(SyntaxKind.GetAccessorDeclaration)));
125 if (classProperty.SetMethod !=
null)
127 return DetermineIfPropertyUsesField(
128 context, fieldSymbol, classProperty,
129 propertyNode => propertyNode.AccessorList.Accessors.Single(
130 _ => _.IsKind(SyntaxKind.SetAccessorDeclaration)));
override void Initialize(AnalysisContext context)
override ImmutableArray< DiagnosticDescriptor > SupportedDiagnostics