static void VerifyProperty(DiagnosticsReportContext context, IPropertySymbol property, HashSet <ITypeSymbol> alreadyAnalyzed, HashSet <int> definedIndexes) { if (property.DeclaredAccessibility != Accessibility.Public) { return; } var attributes = property.GetAttributes(); if (attributes.FindAttributeShortName(IgnoreShortName) != null) { return; } if (property.FindAttributeIncludeBasePropertyShortName(UnionKeyAttributeShortName) != null) { return; } if (!property.IsVirtual && !property.ContainingType.IsValueType) { if (property.IsOverride && !property.IsSealed) { // ok, base type's override property. } else { context.Add(Diagnostic.Create(PublicPropertyMustBeVirtual, property.Locations[0], property.ContainingType?.Name, property.Name)); return; } } var indexAttr = attributes.FindAttributeShortName(IndexAttributeShortName); if (indexAttr == null || indexAttr.ConstructorArguments.Length == 0) { context.Add(Diagnostic.Create(PublicPropertyNeedsIndex, property.Locations[0], property.ContainingType?.Name, property.Name)); return; } var index = indexAttr.ConstructorArguments[0]; if (index.IsNull) { return; // null is normal compiler error. } if (!definedIndexes.Add((int)index.Value)) { context.Add(Diagnostic.Create(IndexAttributeDuplicate, property.Locations[0], property.ContainingType?.Name, property.Name, index.Value)); return; } if ((int)index.Value >= 100) { context.Add(Diagnostic.Create(IndexIsTooLarge, property.Locations[0], index.Value, property.Name)); } if (!property.ContainingType.IsValueType) { if (property.GetMethod == null || property.SetMethod == null || property.GetMethod.DeclaredAccessibility == Accessibility.Private || property.SetMethod.DeclaredAccessibility == Accessibility.Private) { context.Add(Diagnostic.Create(PublicPropertyNeedsGetAndSetAccessor, property.Locations[0], property.ContainingType?.Name, property.Name)); return; } } var namedType = property.Type as INamedTypeSymbol; if (namedType != null) // if <T> is unnamed type, it can't analyze. { VerifyType(context, property.Locations[0], property.Type, alreadyAnalyzed, property); } }