public override void Initialize(AnalysisContext context) { context.ConfigureGeneratedCodeAnalysis(GeneratedCodeAnalysisFlags.None); context.EnableConcurrentExecution(); context.RegisterCompilationStartAction(startCompilation => { var locator = new ReflectionTypeSymbolLocator(startCompilation.Compilation); var attr = new ConcurrentBag <(DiagnosticDescriptor Descriptor, ISymbol Member)>(); if (!DiagnosticGroupTypeAnalysis.TryGetAnalysis(locator, startCompilation.CancellationToken, out var typeAnalysis)) { return; } if (!DiagnosticMemberTypeAnalysis.TryGetAnalysis(locator, startCompilation.CancellationToken, out var memberAnalysis)) { return; } startCompilation.RegisterSymbolAction(context => { if (!(context.Symbol is INamedTypeSymbol namedTypeSymbol)) { return; } if (!context.Symbol.GetAttributes().Any(x => x.AttributeClass.Equals <DiagnosticGroupAttribute>(locator))) { return; } var group = typeAnalysis.VerifyType(namedTypeSymbol, context.ReportDiagnostic); foreach (var member in namedTypeSymbol.GetMembers().Where(x => x is IPropertySymbol || x is IFieldSymbol)) { var descriptionAttribute = memberAnalysis.GetMemberSymbolAttribute(member, context.ReportDiagnostic); if (descriptionAttribute is null || group is null) { continue; } attr.Add((descriptionAttribute.GetDescriptor(group), member)); } }, SymbolKind.NamedType); startCompilation.RegisterSymbolAction(context => { if (!(context.Symbol is IPropertySymbol) && !(context.Symbol is IFieldSymbol)) { return; } // Inspect if member has DiagnosticDescriptionAttribute var memberAttr = context.Symbol.GetAttributes().FirstOrDefault(x => x.AttributeClass.Equals <DiagnosticDescriptionAttribute>(locator)); if (memberAttr is null) { return; } if (!(context.Symbol.ContainingType is INamedTypeSymbol hostingType)) { return; } if (hostingType.GetAttributes().Any(x => x.AttributeClass.Equals <DiagnosticGroupAttribute>(locator))) { return; } // Report diagnostic on how the diagnostic group is missing on the tpye var memberAttrLocation = memberAttr.ApplicationSyntaxReference?.GetSyntax(context.CancellationToken).GetLocation(); context.ReportDiagnostic(DiagnosticSource.MemberShouldBeInGroup(context.Symbol, memberAttrLocation)); }, SymbolKind.Property, SymbolKind.Field); startCompilation.RegisterCompilationEndAction(context => { foreach (var group in attr.GroupBy(x => x.Descriptor.Id)) { if (group.Count() <= 1) { continue; } foreach (var(descriptor, member) in group.ToList()) { context.ReportDiagnostic(DiagnosticSource.DuplicateDiagnosticDescriptor(member, group.Select(x => x.Member), descriptor.Id)); } } }); }); }