microsoft / Power-Fx

Power Fx low-code programming language
MIT License
3.18k stars 321 forks source link

Get suggestions from the formula, throws StackOverFlow exception in TextFirst mode #2456

Closed gekarapa closed 2 months ago

gekarapa commented 3 months ago

The following test case will throw a StackOverFlow exception:

namespace Microsoft.PowerFx.Tests
{
    public class GetSuggestionsTests : PowerFxTest
    {
        [Fact]
        public void GetSuggestionsWithRecursiveRecordTest()
        {

            var parserOptions = new ParserOptions()
            {
                Culture = System.Globalization.CultureInfo.InvariantCulture,
                AllowsSideEffects = true,
                TextFirst = true
            };

            var config = new PowerFxConfig();
            var engine = new Microsoft.PowerFx.Engine(config);

            var lazyTypeInstance = new LazyRecursiveRecordType();

            var res = engine.Check("=Filter(T,", lazyTypeInstance, parserOptions);
            var results = engine.Suggest(res, 10);
        }

        internal class LazyRecursiveRecordType : RecordType
        {
            public override IEnumerable<string> FieldNames => GetFieldNames();

            public bool EnumerableIterated = false;

            public LazyRecursiveRecordType()
                : base()
            {
            }

            public override bool TryGetFieldType(string name, out FormulaType type)
            {
                switch (name)
                {
                    case "SomeString":
                        type = FormulaType.String;
                        return true;
                    case "Loop":
                        type = this;
                        return true;

                    case "T":
                        type = this.ToTable();
                        return true;
                    default:
                        type = FormulaType.Blank;
                        return false;
                }
            }

            private IEnumerable<string> GetFieldNames()
            {
                EnumerableIterated = true;

                yield return "SomeString";
                yield return "Loop";
            }

            public override bool Equals(object other)
            {
                return other is LazyRecursiveRecordType; // All the same 
            }

            public override int GetHashCode()
            {
                return 1;
            }
        }
    }
}
MikeStall commented 3 months ago

FYI, some existing related tests: https://github.com/microsoft/Power-Fx/blob/5126fb4b11c627d83e8da2b38a16b153b4660c9f/src/tests/Microsoft.PowerFx.Interpreter.Tests.Shared/MarshalTests.cs#L150

https://github.com/microsoft/Power-Fx/blob/5126fb4b11c627d83e8da2b38a16b153b4660c9f/src/tests/Microsoft.PowerFx.Core.Tests.Shared/IntellisenseTests/SuggestTest.cs#L385