123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208 |
- using System.Diagnostics.CodeAnalysis;
- using System.Globalization;
- using System.Reflection;
- using Jint.Native;
- using Jint.Native.Object;
- using Jint.Runtime.Descriptors;
- #pragma warning disable IL3050
- namespace Jint.Runtime.Interop;
- /// <summary>
- /// Any instance on this class represents a reference to a CLR namespace.
- /// Accessing its properties will look for a class of the full name, or instantiate
- /// a new <see cref="NamespaceReference"/> as it assumes that the property is a deeper
- /// level of the current namespace
- /// </summary>
- [RequiresUnreferencedCode("Dynamic loading")]
- public class NamespaceReference : ObjectInstance, ICallable
- {
- private readonly string? _path;
- public NamespaceReference(Engine engine, string? path) : base(engine)
- {
- _path = path;
- }
- public override bool DefineOwnProperty(JsValue property, PropertyDescriptor desc)
- {
- return false;
- }
- public override bool Delete(JsValue property)
- {
- return false;
- }
- JsValue ICallable.Call(JsValue thisObject, params JsCallArguments arguments)
- {
- // direct calls on a NamespaceReference constructor object is creating a generic type
- var genericTypes = new Type[arguments.Length];
- for (int i = 0; i < arguments.Length; i++)
- {
- var genericTypeReference = arguments[i];
- if (genericTypeReference.IsUndefined()
- || !genericTypeReference.IsObject()
- || genericTypeReference.AsObject() is not TypeReference tr)
- {
- Throw.TypeError(_engine.Realm, "Invalid generic type parameter on " + _path + ", if this is not a generic type / method, are you missing a lookup assembly?");
- return default;
- }
- genericTypes[i] = tr.ReferenceType;
- }
- var typeReference = GetPath(_path + "`" + arguments.Length.ToString(CultureInfo.InvariantCulture)).As<TypeReference>();
- if (typeReference is null)
- {
- return Undefined;
- }
- try
- {
- var genericType = typeReference.ReferenceType.MakeGenericType(genericTypes);
- return TypeReference.CreateTypeReference(Engine, genericType);
- }
- catch (Exception e)
- {
- Throw.InvalidOperationException($"Invalid generic type parameter on {_path}, if this is not a generic type / method, are you missing a lookup assembly?", e);
- return null;
- }
- }
- public override JsValue Get(JsValue property, JsValue receiver)
- {
- var newPath = string.IsNullOrEmpty(_path)
- ? property.ToString()
- : $"{_path}.{property}";
- return GetPath(newPath);
- }
- [RequiresUnreferencedCode("Dynamic loading")]
- public JsValue GetPath(string path)
- {
- if (_engine.TypeCache.TryGetValue(path, out var type))
- {
- if (type == null)
- {
- return new NamespaceReference(_engine, path);
- }
- return TypeReference.CreateTypeReference(_engine, type);
- }
- // in CoreCLR, for example, classes that used to be in
- // mscorlib were moved away, and only stubs remained, because
- // of that, we do the search on the lookup assemblies first,
- // and only then in mscorlib. Probelm usage: System.IO.File.CreateText
- // search in loaded assemblies
- var lookupAssemblies = new[] { Assembly.GetCallingAssembly(), Assembly.GetExecutingAssembly() };
- foreach (var assembly in lookupAssemblies)
- {
- type = assembly.GetType(path);
- if (type != null)
- {
- _engine.TypeCache.Add(path, type);
- return TypeReference.CreateTypeReference(_engine, type);
- }
- }
- // search in lookup assemblies
- var comparedPath = path.Replace('+', '.');
- foreach (var assembly in _engine.Options.Interop.AllowedAssemblies)
- {
- type = assembly.GetType(path);
- if (type != null)
- {
- _engine.TypeCache.Add(path, type);
- return TypeReference.CreateTypeReference(_engine, type);
- }
- var lastPeriodPos = path.LastIndexOf('.');
- if (lastPeriodPos != -1)
- {
- var trimPath = path.Substring(0, lastPeriodPos);
- type = GetType(assembly, trimPath);
- }
- if (type != null)
- {
- foreach (Type nType in GetAllNestedTypes(type))
- {
- if (nType.FullName != null && nType.FullName.Replace('+', '.').Equals(comparedPath, StringComparison.Ordinal))
- {
- _engine.TypeCache.Add(comparedPath, nType);
- return TypeReference.CreateTypeReference(_engine, nType);
- }
- }
- }
- }
- // search for type in mscorlib
- type = System.Type.GetType(path);
- if (type != null)
- {
- _engine.TypeCache.Add(path, type);
- return TypeReference.CreateTypeReference(_engine, type);
- }
- // the new path doesn't represent a known class, thus return a new namespace instance
- _engine.TypeCache.Add(path, null);
- return new NamespaceReference(_engine, path);
- }
- /// <summary> Gets a type. </summary>
- ///<remarks>Nested type separators are converted to '.' instead of '+' </remarks>
- /// <param name="assembly"> The assembly. </param>
- /// <param name="typeName"> Name of the type. </param>
- ///
- /// <returns> The type. </returns>
- [RequiresUnreferencedCode("Assembly type loading")]
- private static Type? GetType(Assembly assembly, string typeName)
- {
- var compared = typeName.Replace('+', '.');
- foreach (Type t in assembly.GetTypes())
- {
- if (string.Equals(t.FullName?.Replace('+', '.'), compared, StringComparison.Ordinal))
- {
- return t;
- }
- }
- return null;
- }
- private static Type[] GetAllNestedTypes(Type type)
- {
- var types = new List<Type>();
- AddNestedTypesRecursively(types, type);
- return types.ToArray();
- }
- private static void AddNestedTypesRecursively(
- List<Type> types,
- [DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicNestedTypes)] Type type)
- {
- foreach (var nestedType in type.GetNestedTypes(BindingFlags.Public))
- {
- types.Add(nestedType);
- AddNestedTypesRecursively(types, nestedType);
- }
- }
- public override PropertyDescriptor GetOwnProperty(JsValue property)
- {
- return PropertyDescriptor.Undefined;
- }
- public override string ToString()
- {
- return "[CLR namespace: " + _path + "]";
- }
- }
|