private static void AnalyzeNode()

in packages/@jsii/dotnet-runtime/src/Amazon.JSII.Analyzers/JsiiOptionalAnalyzer.cs [39:103]


        private static void AnalyzeNode(SyntaxNodeAnalysisContext context)
        {
            var objectCreation = (ObjectCreationExpressionSyntax)context.Node;
            var typeInfo = context.SemanticModel.GetTypeInfo(objectCreation);
            if (IsJsiiDatatype(typeInfo))
            {
                // If the newly created instance is a Jsii datatype [JsiiByValue]
                // Get all the properties passed
                var passedProperties = new HashSet<string>();
                foreach (var child in objectCreation.ChildNodes())
                {
                    if (child.Kind() == SyntaxKind.ObjectInitializerExpression)
                    {
                        // This is an inline initialization
                        // Saving all the properties that are passed when initializing the props object
                        foreach (var passedProperty in child.ChildNodes().Where(n => n.Kind() == SyntaxKind.SimpleAssignmentExpression))
                        {
                            var props = passedProperty.ChildNodes().ToArray();
                            if (props.Length >= 2)
                            {
                                // Property = value
                                if (props[1].ToString() != "null") // value != null ?
                                {
                                    var propName = props[0].ToString();
                                    passedProperties.Add(propName);
                                }
                            }
                        }
                    }
                }

                // Parent.Parent.Parent = new Construct() instruction.
                // #1 Parent = Argument
                // #2 Parent = ArgumentList
                // #3 Parent = ObjectCreationExpressionSyntax (if it exists).
                var parentType = context.SemanticModel.GetTypeInfo(objectCreation.Parent.Parent.Parent);

                // If the object initialization was an empty newProps() outside of a JsiiClass - We don't fail
                if (passedProperties.Count == 0 && (parentType.Type == null || !IsJsiiClass(parentType)))
                    return;

                // Get all the required properties on the prop object
                var requiredProperties = typeInfo.Type.GetMembers()
                    .Where(m => m.Kind == SymbolKind.Property
                                && !IsJsiiOptionalProperty(m));
                foreach (var requiredProperty in requiredProperties)
                {
                    // The property in the props class IS NOT optional, check if it is passed as an argument.
                    if (!passedProperties.Contains(requiredProperty.Name))
                    {
                        // This property IS REQUIRED and was not passed in the arguments. Raising an error
                        var rule = new DiagnosticDescriptor(DiagnosticId,
                            Title,
                            string.Format(CultureInfo.InvariantCulture, MessageFormatWithPropertyName,
                                requiredProperty.Name),
                            Category,
                            DiagnosticSeverity.Error,
                            isEnabledByDefault: true,
                            description: string.Format(CultureInfo.InvariantCulture, DescriptionWithPropertyName,
                                requiredProperty.Name));
                        context.ReportDiagnostic(Diagnostic.Create(rule, context.Node.GetLocation()));
                    }
                }
            }
        }