Explorar o código

Include interface's extended interfaces in interop property search (#1654)

Marko Lahma hai 1 ano
pai
achega
0cf15010e0
Modificáronse 2 ficheiros con 83 adicións e 14 borrados
  1. 48 0
      Jint.Tests/Runtime/InteropTests.cs
  2. 35 14
      Jint/Runtime/Interop/TypeResolver.cs

+ 48 - 0
Jint.Tests/Runtime/InteropTests.cs

@@ -3283,5 +3283,53 @@ try {
 
             Assert.True(res.AsBoolean());
         }
+
+        public interface IIndexer<out T>
+        {
+            T this[int index] { get; }
+        }
+
+        public interface ICountable<out T>
+        {
+            int Count { get; }
+        }
+
+        public interface IStringCollection : IIndexer<string>, ICountable<string>
+        {
+            string this[string name] { get; }
+        }
+
+        public class Strings : IStringCollection
+        {
+            private readonly string[] _strings;
+            public Strings(string[] strings)
+            {
+                _strings = strings;
+            }
+            public string this[string name]
+            {
+                get
+                {
+                    return int.TryParse(name, out var index) ? _strings[index] : _strings.FirstOrDefault(x => x.Contains(name));
+                }
+            }
+
+            public string this[int index] => _strings[index];
+            public int Count => _strings.Length;
+        }
+
+        public class Utils
+        {
+            public IStringCollection GetStrings() => new Strings(new [] { "a", "b", "c" });
+        }
+
+        [Fact]
+        public void AccessingInterfaceShouldContainExtendedInterfaces()
+        {
+            var engine = new Engine();
+            engine.SetValue("Utils", new Utils());
+            var result = engine.Evaluate("const strings = Utils.GetStrings(); strings.Count;").AsNumber();
+            Assert.Equal(3, result);
+        }
     }
 }

+ 35 - 14
Jint/Runtime/Interop/TypeResolver.cs

@@ -212,29 +212,50 @@ namespace Jint.Runtime.Interop
             PropertyInfo? property = null;
             var memberNameComparer = MemberNameComparer;
             var typeResolverMemberNameCreator = MemberNameCreator;
-            foreach (var p in type.GetProperties(bindingFlags))
+
+            PropertyInfo? GetProperty(Type t)
             {
-                if (!Filter(engine, p))
+                foreach (var p in t.GetProperties(bindingFlags))
                 {
-                    continue;
-                }
+                    if (!Filter(engine, p))
+                    {
+                        continue;
+                    }
 
-                // only if it's not an indexer, we can do case-ignoring matches
-                var isStandardIndexer = p.GetIndexParameters().Length == 1 && p.Name == "Item";
-                if (!isStandardIndexer)
-                {
-                    foreach (var name in typeResolverMemberNameCreator(p))
+                    // only if it's not an indexer, we can do case-ignoring matches
+                    var isStandardIndexer = p.GetIndexParameters().Length == 1 && p.Name == "Item";
+                    if (!isStandardIndexer)
                     {
-                        if (memberNameComparer.Equals(name, memberName))
+                        foreach (var name in typeResolverMemberNameCreator(p))
                         {
-                            property = p;
-                            break;
+                            if (memberNameComparer.Equals(name, memberName))
+                            {
+                                property = p;
+                                break;
+                            }
                         }
                     }
                 }
+
+                return property;
+            }
+
+            property = GetProperty(type);
+
+            if (property is null && type.IsInterface)
+            {
+                // check inherited interfaces
+                foreach (var iface in type.GetInterfaces())
+                {
+                    property = GetProperty(iface);
+                    if (property is not null)
+                    {
+                        break;
+                    }
+                }
             }
 
-            if (property != null)
+            if (property is not null)
             {
                 accessor = new PropertyAccessor(memberName, property, indexerToTry);
                 return true;
@@ -259,7 +280,7 @@ namespace Jint.Runtime.Interop
                 }
             }
 
-            if (field != null)
+            if (field is not null)
             {
                 accessor = new FieldAccessor(field, memberName, indexerToTry);
                 return true;