private static void Analyze(SymbolAnalysisContext context, FriendClassCompilationData compilation) { if (context.Symbol is not INamedTypeSymbol symbol || !(symbol.TypeKind is TypeKind.Class or TypeKind.Struct)) { return; } AttributeData[] attributes = symbol.GetAttributes(compilation.FriendClassAttribute !).ToArray(); if (attributes.Length == 0) { if (TryGetInvalidConfigurationDiagnostic(symbol, compilation, out Diagnostic? d)) { context.ReportDiagnostic(d); } return; } FriendClassConfiguration config = GetConfiguration(symbol, compilation); if (!ValidateConfiguration(symbol, config, out Diagnostic? diagnostic)) { context.ReportDiagnostic(diagnostic); } foreach (Diagnostic d in AnalyzeAttributes(attributes, symbol, compilation)) { context.ReportDiagnostic(d); } }
private static FriendClassConfiguration GetConfiguration(INamedTypeSymbol symbol, FriendClassCompilationData compilation) { FriendClassConfiguration @default = FriendClassConfiguration.Default; if (symbol.GetAttribute(compilation.FriendClassConfigurationAttribute !) is not AttributeData attr || attr.ApplicationSyntaxReference is null || attr.ApplicationSyntaxReference.GetSyntax() is not AttributeSyntax syntax ) { return(@default); } bool allowsChildren = GetBoolProperty(MemberNames.Config_AllowsChildren, @default.AllowsChildren); return(new() { AllowsChildren = allowsChildren, Syntax = syntax }); bool GetBoolProperty(string name, bool @default) { if (!attr.TryGetNamedArgumentValue(name, out bool value)) { value = @default; } return(value); } }
private static bool ValidateConfiguration( INamedTypeSymbol symbol, FriendClassConfiguration configuration, [NotNullWhen(false)] out Diagnostic?diagnostic ) { if (!configuration.AllowsChildren) { if (configuration.Syntax is not null) { diagnostic = Diagnostic.Create( descriptor: DUR0313_ConfigurationIsRedundant, location: configuration.Syntax.GetLocation(), messageArgs: new[] { symbol } ); return(false); } } else if (symbol.TypeKind == TypeKind.Struct || symbol.IsSealed || symbol.IsStatic) { diagnostic = Diagnostic.Create( descriptor: DUR0311_DoNotAllowChildrenOnSealedType, location: GetArgumentLocation(MemberNames.Config_AllowsChildren), messageArgs: new[] { symbol } ); return(false); } diagnostic = null; return(true); Location GetArgumentLocation(string argName) { if (configuration.Syntax is not null && configuration.Syntax.ArgumentList is not null && configuration.Syntax.ArgumentList.Arguments is SeparatedSyntaxList <AttributeArgumentSyntax> { Count: > 0 } arguments&& arguments.FirstOrDefault(arg => arg.NameEquals is not null && arg.NameEquals.Name.ToString() == argName) is AttributeArgumentSyntax arg ) { return(arg.GetLocation()); } return(symbol.Locations.FirstOrDefault() ?? Location.None); } }