File: IOperationClassWriter.Verifier.cs
Web Access
Project: src\src\Tools\Source\CompilerGeneratorTools\Source\IOperationGenerator\CompilersIOperationGenerator.csproj (IOperationGenerator)
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
 
using System;
using System.Linq;
 
namespace IOperationGenerator
{
    internal sealed partial class IOperationClassWriter
    {
        private bool ModelHasErrors(Tree tree)
        {
            bool error = false;
 
            foreach (var abstractNode in tree.Types.OfType<AbstractNode>())
            {
                if (!abstractNode.Name.StartsWith("I"))
                {
                    Console.WriteLine($"All IOperation node names must start with I. {abstractNode.Name} does not.");
                    error = true;
                }
 
                if (!abstractNode.Name.EndsWith("Operation"))
                {
                    Console.WriteLine($"All IOperation node names must end with Operation. {abstractNode.Name} does not.");
                    error = true;
                }
 
                if (!_typeMap.ContainsKey(abstractNode.Base))
                {
                    Console.WriteLine($"{abstractNode.Name}'s base type is not an IOperation type.");
                    error = true;
                }
 
                if (!abstractNode.IsInternal && abstractNode.Obsolete is null)
                {
                    if (abstractNode.Comments?.Elements?[0].Name != "summary")
                    {
                        Console.WriteLine($"{abstractNode.Name} does not have correctly formatted comments, please ensure that there is a <summary> block for the type.");
                        error = true;
                    }
 
                    foreach (var prop in abstractNode.Properties)
                    {
                        if (prop.Comments?.Elements?[0].Name != "summary" && !prop.IsInternal && !prop.IsOverride)
                        {
                            Console.WriteLine($"{abstractNode.Name}.{prop.Name} does not have correctly formatted comments, please ensure that there is a <summary> block for the property.");
                            error = true;
                        }
                    }
                }
 
                foreach (var prop in GetAllGeneratedIOperationProperties(abstractNode))
                {
                    if (IsImmutableArray(prop.Type, out _) && prop.Type.Contains("?"))
                    {
                        Console.WriteLine($"{abstractNode.Name}.{prop.Name} has nullable IOperation elements. This is not allowed in IOperation and will mess up Children generation.");
                        error = true;
                    }
                }
 
                if (abstractNode is not Node node)
                    continue;
                if (node.SkipChildrenGeneration || node.SkipClassGeneration)
                    continue;
 
                if (node.HasTypeText is not (null or "true" or "false"))
                {
                    Console.WriteLine($"{node.Name} has unexpected value for {nameof(Node.HasType)}: {node.HasTypeText}");
                    error = true;
                }
 
                if (node.HasConstantValueText is not (null or "true" or "false"))
                {
                    Console.WriteLine($"{node.Name} has unexpected value for {nameof(Node.HasConstantValue)}: {node.HasConstantValueText}");
                    error = true;
                }
 
                if (node.HasConstantValue && !node.HasType)
                {
                    Console.WriteLine($"{node.Name} is marked as having a constant value without having a type");
                    error = true;
                }
 
                var properties = GetAllGeneratedIOperationProperties(node).Where(p => !p.IsInternal).Select(p => p.Name).ToList();
 
                if (properties.Count < 2)
                {
                    if (node.ChildrenOrder is string order)
                    {
                        var splitOrder = GetPropertyOrder(node);
 
                        if (splitOrder.Count != properties.Count || (properties.Count == 1 && properties[0] != splitOrder[0]))
                        {
                            Console.WriteLine($"{node.Name} has inconsistent ChildrenOrder and properties");
                            error = true;
                        }
                    }
                    continue;
                }
 
                if (node.ChildrenOrder is null)
                {
                    Console.WriteLine($"{node.Name} has more than 1 IOperation property and must declare an explicit ordering with the ChildrenOrder attribute.");
                    Console.WriteLine($"Properties: {string.Join(", ", properties)}");
                    error = true;
                    continue;
                }
 
                var childrenOrdered = GetPropertyOrder(node);
                foreach (var child in childrenOrdered)
                {
                    if (!properties.Remove(child))
                    {
                        Console.WriteLine($"{node.Name}'s ChildrenOrder contains unknown property {child}");
                        error = true;
                    }
                }
 
                foreach (var remainingProp in properties)
                {
                    Console.WriteLine($"{node.Name}'s ChildrenOrder is missing {remainingProp}");
                    error = true;
                }
            }
 
            return error;
        }
    }
}