| File: Parser.cs | Web Access |
| Project: src\src\Generators\Microsoft.Gen.ContextualOptions\Microsoft.Gen.ContextualOptions.csproj (Microsoft.Gen.ContextualOptions) |
// Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. using System.Collections.Generic; using System.Collections.Immutable; using System.Linq; using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.CSharp; using Microsoft.CodeAnalysis.CSharp.Syntax; using Microsoft.Gen.ContextualOptions.Model; namespace Microsoft.Gen.ContextualOptions; internal static class Parser { public static IEnumerable<OptionsContextType> GetContextualOptionTypes(Dictionary<INamedTypeSymbol, List<TypeDeclarationSyntax>> types) => types .Select(type => new OptionsContextType(type.Key, type.Value.ToImmutableArray(), GetContextProperties(type.Key))) .Select(CheckInstantiable) .Select(CheckPartial) .Select(CheckRefLikeType) .Select(CheckHasProperties); private static OptionsContextType CheckInstantiable(OptionsContextType type) { if (type.Symbol.IsStatic) { type.Diagnostics.AddRange( type.Definitions .SelectMany(def => def.Modifiers) .Where(modifier => modifier.IsKind(SyntaxKind.StaticKeyword)) .Select(modifier => Diagnostic.Create(DiagDescriptors.ContextCannotBeStatic, modifier.GetLocation(), type.Name))); } return type; } private static OptionsContextType CheckRefLikeType(OptionsContextType type) { if (type.Symbol.IsRefLikeType) { type.Diagnostics.AddRange( type.Definitions .SelectMany(def => def.Modifiers) .Where(modifier => modifier.IsKind(SyntaxKind.RefKeyword)) .Select(modifier => Diagnostic.Create(DiagDescriptors.ContextCannotBeRefLike, modifier.GetLocation(), type.Name))); } return type; } private static OptionsContextType CheckPartial(OptionsContextType type) { if (!type.Definitions.Any(def => def.Modifiers.Any(static token => token.IsKind(SyntaxKind.PartialKeyword)))) { type.Diagnostics.AddRange( type.Definitions.Select(def => Diagnostic.Create(DiagDescriptors.ContextMustBePartial, def.Identifier.GetLocation(), type.Name))); } return type; } private static OptionsContextType CheckHasProperties(OptionsContextType type) { if (type.OptionsContextProperties.IsEmpty) { type.Diagnostics.AddRange( type.Definitions.Select(def => Diagnostic.Create(DiagDescriptors.ContextDoesNotHaveValidProperties, def.Identifier.GetLocation(), type.Name))); } return type; } private static ImmutableArray<string> GetContextProperties(INamedTypeSymbol symbol) { return symbol .GetMembers() .OfType<IPropertySymbol>() .Where(prop => !prop.IsStatic) .Where(prop => !prop.IsWriteOnly) .Where(prop => !prop.Type.IsRefLikeType) .Where(prop => prop.Type.TypeKind != TypeKind.Pointer) .Where(prop => prop.Type.TypeKind != TypeKind.FunctionPointer) .Where(prop => prop.Parameters.IsEmpty) .Where(prop => prop.ExplicitInterfaceImplementations.IsEmpty) .Where(GetterIsPublic) .Select(prop => prop.Name) .ToImmutableArray(); static bool GetterIsPublic(IPropertySymbol prop) => prop.GetMethod!.DeclaredAccessibility == Accessibility.Public; } }