PageRenderTime 52ms CodeModel.GetById 17ms RepoModel.GetById 0ms app.codeStats 0ms

/Languages/IronPython/IronPython/Runtime/Operations/PythonTypeOps.cs

http://github.com/IronLanguages/main
C# | 923 lines | 686 code | 161 blank | 76 comment | 217 complexity | 301ce9977de98467474148a9b944e48e MD5 | raw file
Possible License(s): CPL-1.0, BSD-3-Clause, ISC, GPL-2.0, MPL-2.0-no-copyleft-exception
  1. /* ****************************************************************************
  2. *
  3. * Copyright (c) Microsoft Corporation.
  4. *
  5. * This source code is subject to terms and conditions of the Apache License, Version 2.0. A
  6. * copy of the license can be found in the License.html file at the root of this distribution. If
  7. * you cannot locate the Apache License, Version 2.0, please send an email to
  8. * dlr@microsoft.com. By using this source code in any fashion, you are agreeing to be bound
  9. * by the terms of the Apache License, Version 2.0.
  10. *
  11. * You must not remove this notice, or any other, from this software.
  12. *
  13. *
  14. * ***************************************************************************/
  15. using System;
  16. using System.Collections.Generic;
  17. using System.Diagnostics;
  18. using System.Reflection;
  19. using System.Dynamic;
  20. using System.Linq;
  21. using IronPython.Runtime.Binding;
  22. using IronPython.Runtime.Types;
  23. using Microsoft.Scripting;
  24. using Microsoft.Scripting.Actions;
  25. using Microsoft.Scripting.Generation;
  26. using Microsoft.Scripting.Runtime;
  27. using Microsoft.Scripting.Utils;
  28. namespace IronPython.Runtime.Operations {
  29. internal static class PythonTypeOps {
  30. private static readonly Dictionary<FieldInfo, PythonTypeSlot> _fieldCache = new Dictionary<FieldInfo, PythonTypeSlot>();
  31. private static readonly Dictionary<BuiltinFunction, BuiltinMethodDescriptor> _methodCache = new Dictionary<BuiltinFunction, BuiltinMethodDescriptor>();
  32. private static readonly Dictionary<BuiltinFunction, ClassMethodDescriptor> _classMethodCache = new Dictionary<BuiltinFunction, ClassMethodDescriptor>();
  33. internal static readonly Dictionary<BuiltinFunctionKey, BuiltinFunction> _functions = new Dictionary<BuiltinFunctionKey, BuiltinFunction>();
  34. private static readonly Dictionary<ReflectionCache.MethodBaseCache, ConstructorFunction> _ctors = new Dictionary<ReflectionCache.MethodBaseCache, ConstructorFunction>();
  35. private static readonly Dictionary<EventTracker, ReflectedEvent> _eventCache = new Dictionary<EventTracker, ReflectedEvent>();
  36. internal static readonly Dictionary<PropertyTracker, ReflectedGetterSetter> _propertyCache = new Dictionary<PropertyTracker, ReflectedGetterSetter>();
  37. internal static PythonTuple MroToPython(IList<PythonType> types) {
  38. List<object> res = new List<object>(types.Count);
  39. foreach (PythonType dt in types) {
  40. if (dt.UnderlyingSystemType == typeof(ValueType)) continue; // hide value type
  41. if(dt.OldClass != null) {
  42. res.Add(dt.OldClass);
  43. } else {
  44. res.Add(dt);
  45. }
  46. }
  47. return PythonTuple.Make(res);
  48. }
  49. internal static string GetModuleName(CodeContext/*!*/ context, Type type) {
  50. Type curType = type;
  51. while (curType != null) {
  52. string moduleName;
  53. if (PythonContext.GetContext(context).BuiltinModuleNames.TryGetValue(curType, out moduleName)) {
  54. return moduleName;
  55. }
  56. curType = curType.DeclaringType;
  57. }
  58. FieldInfo modField = type.GetField("__module__");
  59. if (modField != null && modField.IsLiteral && modField.FieldType == typeof(string)) {
  60. return (string)modField.GetRawConstantValue();
  61. }
  62. return "__builtin__";
  63. }
  64. internal static object CallParams(CodeContext/*!*/ context, PythonType cls, params object[] args\u03c4) {
  65. if (args\u03c4 == null) args\u03c4 = ArrayUtils.EmptyObjects;
  66. return CallWorker(context, cls, args\u03c4);
  67. }
  68. internal static object CallWorker(CodeContext/*!*/ context, PythonType dt, object[] args) {
  69. object newObject = PythonOps.CallWithContext(context, GetTypeNew(context, dt), ArrayUtils.Insert<object>(dt, args));
  70. if (ShouldInvokeInit(dt, DynamicHelpers.GetPythonType(newObject), args.Length)) {
  71. PythonOps.CallWithContext(context, GetInitMethod(context, dt, newObject), args);
  72. AddFinalizer(context, dt, newObject);
  73. }
  74. return newObject;
  75. }
  76. internal static object CallWorker(CodeContext/*!*/ context, PythonType dt, IDictionary<string, object> kwArgs, object[] args) {
  77. object[] allArgs = ArrayOps.CopyArray(args, kwArgs.Count + args.Length);
  78. string[] argNames = new string[kwArgs.Count];
  79. int i = args.Length;
  80. foreach (KeyValuePair<string, object> kvp in kwArgs) {
  81. allArgs[i] = kvp.Value;
  82. argNames[i++ - args.Length] = kvp.Key;
  83. }
  84. return CallWorker(context, dt, new KwCallInfo(allArgs, argNames));
  85. }
  86. internal static object CallWorker(CodeContext/*!*/ context, PythonType dt, KwCallInfo args) {
  87. object[] clsArgs = ArrayUtils.Insert<object>(dt, args.Arguments);
  88. object newObject = PythonOps.CallWithKeywordArgs(context,
  89. GetTypeNew(context, dt),
  90. clsArgs,
  91. args.Names);
  92. if (newObject == null) return null;
  93. if (ShouldInvokeInit(dt, DynamicHelpers.GetPythonType(newObject), args.Arguments.Length)) {
  94. PythonOps.CallWithKeywordArgs(context, GetInitMethod(context, dt, newObject), args.Arguments, args.Names);
  95. AddFinalizer(context, dt, newObject);
  96. }
  97. return newObject;
  98. }
  99. /// <summary>
  100. /// Looks up __init__ avoiding calls to __getattribute__ and handling both
  101. /// new-style and old-style classes in the MRO.
  102. /// </summary>
  103. private static object GetInitMethod(CodeContext/*!*/ context, PythonType dt, object newObject) {
  104. // __init__ is never searched for w/ __getattribute__
  105. for (int i = 0; i < dt.ResolutionOrder.Count; i++) {
  106. PythonType cdt = dt.ResolutionOrder[i];
  107. PythonTypeSlot dts;
  108. object value;
  109. if (cdt.IsOldClass) {
  110. OldClass oc = PythonOps.ToPythonType(cdt) as OldClass;
  111. if (oc != null && oc.TryGetBoundCustomMember(context, "__init__", out value)) {
  112. return oc.GetOldStyleDescriptor(context, value, newObject, oc);
  113. }
  114. // fall through to new-style only case. We might accidently
  115. // detect old-style if the user imports a IronPython.NewTypes
  116. // type.
  117. }
  118. if (cdt.TryLookupSlot(context, "__init__", out dts) &&
  119. dts.TryGetValue(context, newObject, dt, out value)) {
  120. return value;
  121. }
  122. }
  123. return null;
  124. }
  125. private static void AddFinalizer(CodeContext/*!*/ context, PythonType dt, object newObject) {
  126. // check if object has finalizer...
  127. PythonTypeSlot dummy;
  128. if (dt.TryResolveSlot(context, "__del__", out dummy)) {
  129. IWeakReferenceable iwr = context.GetPythonContext().ConvertToWeakReferenceable(newObject);
  130. Debug.Assert(iwr != null);
  131. InstanceFinalizer nif = new InstanceFinalizer(context, newObject);
  132. iwr.SetFinalizer(new WeakRefTracker(iwr, nif, nif));
  133. }
  134. }
  135. private static object GetTypeNew(CodeContext/*!*/ context, PythonType dt) {
  136. PythonTypeSlot dts;
  137. if (!dt.TryResolveSlot(context, "__new__", out dts)) {
  138. throw PythonOps.TypeError("cannot create instances of {0}", dt.Name);
  139. }
  140. object newInst;
  141. bool res = dts.TryGetValue(context, dt, dt, out newInst);
  142. Debug.Assert(res);
  143. return newInst;
  144. }
  145. internal static bool IsRuntimeAssembly(Assembly assembly) {
  146. if (assembly == typeof(PythonOps).GetTypeInfo().Assembly || // IronPython.dll
  147. assembly == typeof(Microsoft.Scripting.Interpreter.LightCompiler).GetTypeInfo().Assembly || // Microsoft.Scripting.dll
  148. assembly == typeof(DynamicMetaObject).GetTypeInfo().Assembly) { // Microsoft.Scripting.Core.dll
  149. return true;
  150. }
  151. AssemblyName assemblyName = new AssemblyName(assembly.FullName);
  152. if (assemblyName.Name.Equals("IronPython.Modules")) { // IronPython.Modules.dll
  153. return true;
  154. }
  155. return false;
  156. }
  157. private static bool ShouldInvokeInit(PythonType cls, PythonType newObjectType, int argCnt) {
  158. // don't run __init__ if it's not a subclass of ourselves,
  159. // or if this is the user doing type(x), or if it's a standard
  160. // .NET type which doesn't have an __init__ method (this is a perf optimization)
  161. return (!cls.IsSystemType || cls.IsPythonType) &&
  162. newObjectType.IsSubclassOf(cls) &&
  163. (cls != TypeCache.PythonType || argCnt > 1);
  164. }
  165. // note: returns "instance" rather than type name if o is an OldInstance
  166. internal static string GetName(object o) {
  167. // Resolve Namespace-Tracker name, which would end in `namespace#` if
  168. // it is not handled indivdualy
  169. if (o is NamespaceTracker)
  170. {
  171. return ((NamespaceTracker)o).Name;
  172. }
  173. return DynamicHelpers.GetPythonType(o).Name;
  174. }
  175. // a version of GetName that also works on old-style classes
  176. internal static string GetOldName(object o) {
  177. return o is OldInstance ? GetOldName((OldInstance)o) : GetName(o);
  178. }
  179. // a version of GetName that also works on old-style classes
  180. internal static string GetOldName(OldInstance instance) {
  181. return instance._class.Name;
  182. }
  183. internal static PythonType[] ObjectTypes(object[] args) {
  184. PythonType[] types = new PythonType[args.Length];
  185. for (int i = 0; i < args.Length; i++) {
  186. types[i] = DynamicHelpers.GetPythonType(args[i]);
  187. }
  188. return types;
  189. }
  190. internal static Type[] ConvertToTypes(PythonType[] pythonTypes) {
  191. Type[] types = new Type[pythonTypes.Length];
  192. for (int i = 0; i < pythonTypes.Length; i++) {
  193. types[i] = ConvertToType(pythonTypes[i]);
  194. }
  195. return types;
  196. }
  197. private static Type ConvertToType(PythonType pythonType) {
  198. if (pythonType.IsNull) {
  199. return typeof(DynamicNull);
  200. } else {
  201. return pythonType.UnderlyingSystemType;
  202. }
  203. }
  204. internal static TrackerTypes GetMemberType(MemberGroup members) {
  205. TrackerTypes memberType = TrackerTypes.All;
  206. for (int i = 0; i < members.Count; i++) {
  207. MemberTracker mi = members[i];
  208. if (mi.MemberType != memberType) {
  209. if (memberType != TrackerTypes.All) {
  210. return TrackerTypes.All;
  211. }
  212. memberType = mi.MemberType;
  213. }
  214. }
  215. return memberType;
  216. }
  217. internal static PythonTypeSlot/*!*/ GetSlot(MemberGroup group, string name, bool privateBinding) {
  218. if (group.Count == 0) {
  219. return null;
  220. }
  221. group = FilterNewSlots(group);
  222. TrackerTypes tt = GetMemberType(group);
  223. switch(tt) {
  224. case TrackerTypes.Method:
  225. bool checkStatic = false;
  226. List<MemberInfo> mems = new List<MemberInfo>();
  227. foreach (MemberTracker mt in group) {
  228. MethodTracker metht = (MethodTracker)mt;
  229. mems.Add(metht.Method);
  230. checkStatic |= metht.IsStatic;
  231. }
  232. Type declType = group[0].DeclaringType;
  233. MemberInfo[] memArray = mems.ToArray();
  234. FunctionType ft = GetMethodFunctionType(declType, memArray, checkStatic);
  235. return GetFinalSlotForFunction(GetBuiltinFunction(declType, group[0].Name, name, ft, memArray));
  236. case TrackerTypes.Field:
  237. return GetReflectedField(((FieldTracker)group[0]).Field);
  238. case TrackerTypes.Property:
  239. return GetReflectedProperty((PropertyTracker)group[0], group, privateBinding);
  240. case TrackerTypes.Event:
  241. return GetReflectedEvent(((EventTracker)group[0]));
  242. case TrackerTypes.Type:
  243. TypeTracker type = (TypeTracker)group[0];
  244. for (int i = 1; i < group.Count; i++) {
  245. type = TypeGroup.UpdateTypeEntity(type, (TypeTracker)group[i]);
  246. }
  247. if (type is TypeGroup) {
  248. return new PythonTypeUserDescriptorSlot(type, true);
  249. }
  250. return new PythonTypeUserDescriptorSlot(DynamicHelpers.GetPythonTypeFromType(type.Type), true);
  251. case TrackerTypes.Constructor:
  252. return GetConstructor(group[0].DeclaringType, privateBinding);
  253. case TrackerTypes.Custom:
  254. return ((PythonCustomTracker)group[0]).GetSlot();
  255. default:
  256. // if we have a new slot in the derived class filter out the
  257. // members from the base class.
  258. throw new InvalidOperationException(String.Format("Bad member type {0} on {1}.{2}", tt.ToString(), group[0].DeclaringType, name));
  259. }
  260. }
  261. internal static MemberGroup FilterNewSlots(MemberGroup group) {
  262. if (GetMemberType(group) == TrackerTypes.All) {
  263. Type declType = group[0].DeclaringType;
  264. for (int i = 1; i < group.Count; i++) {
  265. if (group[i].DeclaringType != declType) {
  266. if (group[i].DeclaringType.IsSubclassOf(declType)) {
  267. declType = group[i].DeclaringType;
  268. }
  269. }
  270. }
  271. List<MemberTracker> trackers = new List<MemberTracker>();
  272. for (int i = 0; i < group.Count; i++) {
  273. if (group[i].DeclaringType == declType) {
  274. trackers.Add(group[i]);
  275. }
  276. }
  277. if (trackers.Count != group.Count) {
  278. return new MemberGroup(trackers.ToArray());
  279. }
  280. }
  281. return group;
  282. }
  283. private static BuiltinFunction GetConstructor(Type t, bool privateBinding) {
  284. BuiltinFunction ctorFunc = InstanceOps.NonDefaultNewInst;
  285. MethodBase[] ctors = CompilerHelpers.GetConstructors(t, privateBinding, true);
  286. return GetConstructor(t, ctorFunc, ctors);
  287. }
  288. internal static bool IsDefaultNew(MethodBase[] targets) {
  289. if (targets.Length == 1) {
  290. ParameterInfo[] pis = targets[0].GetParameters();
  291. if (pis.Length == 0) {
  292. return true;
  293. }
  294. if (pis.Length == 1 && pis[0].ParameterType == typeof(CodeContext)) {
  295. return true;
  296. }
  297. }
  298. return false;
  299. }
  300. internal static BuiltinFunction GetConstructorFunction(Type type, string name) {
  301. List<MethodBase> methods = new List<MethodBase>();
  302. bool hasDefaultConstructor = false;
  303. foreach (ConstructorInfo ci in type.GetConstructors(BindingFlags.Public | BindingFlags.Instance)) {
  304. if (ci.IsPublic) {
  305. if (ci.GetParameters().Length == 0) {
  306. hasDefaultConstructor = true;
  307. }
  308. methods.Add(ci);
  309. }
  310. }
  311. if (type.IsValueType() && !hasDefaultConstructor && type != typeof(void)) {
  312. try {
  313. methods.Add(typeof(ScriptingRuntimeHelpers).GetMethod("CreateInstance", ReflectionUtils.EmptyTypes).MakeGenericMethod(type));
  314. } catch (BadImageFormatException) {
  315. // certain types (e.g. ArgIterator) won't survive the above call.
  316. // we won't let you create instances of these types.
  317. }
  318. }
  319. if (methods.Count > 0) {
  320. return BuiltinFunction.MakeFunction(name, methods.ToArray(), type);
  321. }
  322. return null;
  323. }
  324. internal static ReflectedEvent GetReflectedEvent(EventTracker tracker) {
  325. ReflectedEvent res;
  326. lock (_eventCache) {
  327. if (!_eventCache.TryGetValue(tracker, out res)) {
  328. if (PythonBinder.IsExtendedType(tracker.DeclaringType)) {
  329. _eventCache[tracker] = res = new ReflectedEvent(tracker, true);
  330. } else {
  331. _eventCache[tracker] = res = new ReflectedEvent(tracker, false);
  332. }
  333. }
  334. }
  335. return res;
  336. }
  337. internal static PythonTypeSlot/*!*/ GetFinalSlotForFunction(BuiltinFunction/*!*/ func) {
  338. if ((func.FunctionType & FunctionType.Method) != 0) {
  339. BuiltinMethodDescriptor desc;
  340. lock (_methodCache) {
  341. if (!_methodCache.TryGetValue(func, out desc)) {
  342. _methodCache[func] = desc = new BuiltinMethodDescriptor(func);
  343. }
  344. return desc;
  345. }
  346. }
  347. if (func.Targets[0].IsDefined(typeof(ClassMethodAttribute), true)) {
  348. lock (_classMethodCache) {
  349. ClassMethodDescriptor desc;
  350. if (!_classMethodCache.TryGetValue(func, out desc)) {
  351. _classMethodCache[func] = desc = new ClassMethodDescriptor(func);
  352. }
  353. return desc;
  354. }
  355. }
  356. return func;
  357. }
  358. internal static BuiltinFunction/*!*/ GetBuiltinFunction(Type/*!*/ type, string/*!*/ name, MemberInfo/*!*/[]/*!*/ mems) {
  359. return GetBuiltinFunction(type, name, null, mems);
  360. }
  361. #pragma warning disable 414 // unused fields - they're used by GetHashCode()
  362. internal struct BuiltinFunctionKey {
  363. Type DeclaringType;
  364. ReflectionCache.MethodBaseCache Cache;
  365. FunctionType FunctionType;
  366. public BuiltinFunctionKey(Type declaringType, ReflectionCache.MethodBaseCache cache, FunctionType funcType) {
  367. Cache = cache;
  368. FunctionType = funcType;
  369. DeclaringType = declaringType;
  370. }
  371. }
  372. #pragma warning restore 169
  373. public static MethodBase[] GetNonBaseHelperMethodInfos(MemberInfo[] members) {
  374. List<MethodBase> res = new List<MethodBase>();
  375. foreach (MemberInfo mi in members) {
  376. MethodBase mb = mi as MethodBase;
  377. if (mb != null && !mb.Name.StartsWith(NewTypeMaker.BaseMethodPrefix)) {
  378. res.Add(mb);
  379. }
  380. }
  381. return res.ToArray();
  382. }
  383. public static MemberInfo[] GetNonBaseHelperMemberInfos(MemberInfo[] members) {
  384. List<MemberInfo> res = new List<MemberInfo>(members.Length);
  385. foreach (MemberInfo mi in members) {
  386. MethodBase mb = mi as MethodBase;
  387. if (mb == null || !mb.Name.StartsWith(NewTypeMaker.BaseMethodPrefix)) {
  388. res.Add(mi);
  389. }
  390. }
  391. return res.ToArray();
  392. }
  393. internal static BuiltinFunction/*!*/ GetBuiltinFunction(Type/*!*/ type, string/*!*/ name, FunctionType? funcType, params MemberInfo/*!*/[]/*!*/ mems) {
  394. return GetBuiltinFunction(type, name, name, funcType, mems);
  395. }
  396. /// <summary>
  397. /// Gets a builtin function for the given declaring type and member infos.
  398. ///
  399. /// Given the same inputs this always returns the same object ensuring there's only 1 builtinfunction
  400. /// for each .NET method.
  401. ///
  402. /// This method takes both a cacheName and a pythonName. The cache name is the real method name. The pythonName
  403. /// is the name of the method as exposed to Python.
  404. /// </summary>
  405. internal static BuiltinFunction/*!*/ GetBuiltinFunction(Type/*!*/ type, string/*!*/ cacheName, string/*!*/ pythonName, FunctionType? funcType, params MemberInfo/*!*/[]/*!*/ mems) {
  406. BuiltinFunction res = null;
  407. if (mems.Length != 0) {
  408. FunctionType ft = funcType ?? GetMethodFunctionType(type, mems);
  409. type = GetBaseDeclaringType(type, mems);
  410. BuiltinFunctionKey cache = new BuiltinFunctionKey(type, new ReflectionCache.MethodBaseCache(cacheName, GetNonBaseHelperMethodInfos(mems)), ft);
  411. lock (_functions) {
  412. if (!_functions.TryGetValue(cache, out res)) {
  413. if (PythonTypeOps.GetFinalSystemType(type) == type) {
  414. IList<MethodInfo> overriddenMethods = NewTypeMaker.GetOverriddenMethods(type, cacheName);
  415. if (overriddenMethods.Count > 0) {
  416. List<MemberInfo> newMems = new List<MemberInfo>(mems);
  417. foreach (MethodInfo mi in overriddenMethods) {
  418. newMems.Add(mi);
  419. }
  420. mems = newMems.ToArray();
  421. }
  422. }
  423. _functions[cache] = res = BuiltinFunction.MakeMethod(pythonName, ReflectionUtils.GetMethodInfos(mems), type, ft);
  424. }
  425. }
  426. }
  427. return res;
  428. }
  429. private static Type GetCommonBaseType(Type xType, Type yType) {
  430. if (xType.IsSubclassOf(yType)) {
  431. return yType;
  432. } else if (yType.IsSubclassOf(xType)) {
  433. return xType;
  434. } else if (xType == yType) {
  435. return xType;
  436. }
  437. Type xBase = xType.GetBaseType();
  438. Type yBase = yType.GetBaseType();
  439. if (xBase != null) {
  440. Type res = GetCommonBaseType(xBase, yType);
  441. if (res != null) {
  442. return res;
  443. }
  444. }
  445. if (yBase != null) {
  446. Type res = GetCommonBaseType(xType, yBase);
  447. if (res != null) {
  448. return res;
  449. }
  450. }
  451. return null;
  452. }
  453. private static Type GetBaseDeclaringType(Type type, MemberInfo/*!*/[] mems) {
  454. // get the base most declaring type, first sort the list so that
  455. // the most derived class is at the beginning.
  456. Array.Sort<MemberInfo>(mems, delegate(MemberInfo x, MemberInfo y) {
  457. if (x.DeclaringType.IsSubclassOf(y.DeclaringType)) {
  458. return -1;
  459. } else if (y.DeclaringType.IsSubclassOf(x.DeclaringType)) {
  460. return 1;
  461. } else if (x.DeclaringType == y.DeclaringType) {
  462. return 0;
  463. }
  464. // no relationship between these types, they should be base helper
  465. // methods for two different types - for example object.MemberwiseClone for
  466. // ExtensibleInt & object. We need to reset our type to the common base type.
  467. type = GetCommonBaseType(x.DeclaringType, y.DeclaringType) ?? typeof(object);
  468. // generic type definitions will have a null name.
  469. if (x.DeclaringType.FullName == null) {
  470. return -1;
  471. } else if (y.DeclaringType.FullName == null) {
  472. return 1;
  473. }
  474. return x.DeclaringType.FullName.CompareTo(y.DeclaringType.FullName);
  475. });
  476. // then if the provided type is a subclass of the most derived type
  477. // then our declaring type is the methods declaring type.
  478. foreach (MemberInfo mb in mems) {
  479. // skip extension methods
  480. if (mb.DeclaringType.IsAssignableFrom(type)) {
  481. if (type == mb.DeclaringType || type.IsSubclassOf(mb.DeclaringType)) {
  482. type = mb.DeclaringType;
  483. break;
  484. }
  485. }
  486. }
  487. return type;
  488. }
  489. internal static ConstructorFunction GetConstructor(Type type, BuiltinFunction realTarget, params MethodBase[] mems) {
  490. ConstructorFunction res = null;
  491. if (mems.Length != 0) {
  492. ReflectionCache.MethodBaseCache cache = new ReflectionCache.MethodBaseCache("__new__", mems);
  493. lock (_ctors) {
  494. if (!_ctors.TryGetValue(cache, out res)) {
  495. _ctors[cache] = res = new ConstructorFunction(realTarget, mems);
  496. }
  497. }
  498. }
  499. return res;
  500. }
  501. internal static FunctionType GetMethodFunctionType(Type/*!*/ type, MemberInfo/*!*/[]/*!*/ methods) {
  502. return GetMethodFunctionType(type, methods, true);
  503. }
  504. internal static FunctionType GetMethodFunctionType(Type/*!*/ type, MemberInfo/*!*/[]/*!*/ methods, bool checkStatic) {
  505. FunctionType ft = FunctionType.None;
  506. foreach (MethodInfo mi in methods) {
  507. if (mi.IsStatic && mi.IsSpecialName) {
  508. ParameterInfo[] pis = mi.GetParameters();
  509. if ((pis.Length == 2 && pis[0].ParameterType != typeof(CodeContext)) ||
  510. (pis.Length == 3 && pis[0].ParameterType == typeof(CodeContext))) {
  511. ft |= FunctionType.BinaryOperator;
  512. if (pis[pis.Length - 2].ParameterType != type && pis[pis.Length - 1].ParameterType == type) {
  513. ft |= FunctionType.ReversedOperator;
  514. }
  515. }
  516. }
  517. if (checkStatic && IsStaticFunction(type, mi)) {
  518. ft |= FunctionType.Function;
  519. } else {
  520. ft |= FunctionType.Method;
  521. }
  522. }
  523. if (IsMethodAlwaysVisible(type, methods)) {
  524. ft |= FunctionType.AlwaysVisible;
  525. }
  526. return ft;
  527. }
  528. /// <summary>
  529. /// Checks to see if the provided members are always visible for the given type.
  530. ///
  531. /// This filters out methods such as GetHashCode and Equals on standard .NET
  532. /// types that we expose directly as Python types (e.g. object, string, etc...).
  533. ///
  534. /// It also filters out the base helper overrides that are added for supporting
  535. /// super calls on user defined types.
  536. /// </summary>
  537. private static bool IsMethodAlwaysVisible(Type/*!*/ type, MemberInfo/*!*/[]/*!*/ methods) {
  538. bool alwaysVisible = true;
  539. if (PythonBinder.IsPythonType(type)) {
  540. // only show methods defined outside of the system types (object, string)
  541. foreach (MethodInfo mi in methods) {
  542. if (PythonBinder.IsExtendedType(mi.DeclaringType) ||
  543. PythonBinder.IsExtendedType(mi.GetBaseDefinition().DeclaringType) ||
  544. mi.IsDefined(typeof(PythonHiddenAttribute), false)) {
  545. alwaysVisible = false;
  546. break;
  547. }
  548. }
  549. } else if (typeof(IPythonObject).IsAssignableFrom(type)) {
  550. // check if this is a virtual override helper, if so we
  551. // may need to filter it out.
  552. foreach (MethodInfo mi in methods) {
  553. if (PythonBinder.IsExtendedType(mi.DeclaringType)) {
  554. alwaysVisible = false;
  555. break;
  556. }
  557. }
  558. }
  559. return alwaysVisible;
  560. }
  561. /// <summary>
  562. /// a function is static if it's a static .NET method and it's defined on the type or is an extension method
  563. /// with StaticExtensionMethod decoration.
  564. /// </summary>
  565. private static bool IsStaticFunction(Type type, MethodInfo mi) {
  566. return mi.IsStatic && // method must be truly static
  567. !mi.IsDefined(typeof(WrapperDescriptorAttribute), false) && // wrapper descriptors are instance methods
  568. (mi.DeclaringType.IsAssignableFrom(type) || mi.IsDefined(typeof(StaticExtensionMethodAttribute), false)); // or it's not an extension method or it's a static extension method
  569. }
  570. internal static PythonTypeSlot GetReflectedField(FieldInfo info) {
  571. PythonTypeSlot res;
  572. NameType nt = NameType.Field;
  573. if (!PythonBinder.IsExtendedType(info.DeclaringType) &&
  574. !info.IsDefined(typeof(PythonHiddenAttribute), false)) {
  575. nt |= NameType.PythonField;
  576. }
  577. lock (_fieldCache) {
  578. if (!_fieldCache.TryGetValue(info, out res)) {
  579. if (nt == NameType.PythonField && info.IsLiteral) {
  580. if (info.FieldType == typeof(int)) {
  581. res = new PythonTypeUserDescriptorSlot(
  582. ScriptingRuntimeHelpers.Int32ToObject((int)info.GetRawConstantValue()),
  583. true
  584. );
  585. } else if (info.FieldType == typeof(bool)) {
  586. res = new PythonTypeUserDescriptorSlot(
  587. ScriptingRuntimeHelpers.BooleanToObject((bool)info.GetRawConstantValue()),
  588. true
  589. );
  590. } else {
  591. res = new PythonTypeUserDescriptorSlot(
  592. info.GetValue(null),
  593. true
  594. );
  595. }
  596. } else {
  597. res = new ReflectedField(info, nt);
  598. }
  599. _fieldCache[info] = res;
  600. }
  601. }
  602. return res;
  603. }
  604. internal static string GetDocumentation(Type type) {
  605. // Python documentation
  606. var docAttr = type.GetTypeInfo().GetCustomAttributes(typeof(DocumentationAttribute), false);
  607. if (docAttr != null && docAttr.Any()) {
  608. return ((DocumentationAttribute)docAttr.First()).Documentation;
  609. }
  610. if (type == typeof(DynamicNull)) return null;
  611. // Auto Doc (XML or otherwise)
  612. string autoDoc = DocBuilder.CreateAutoDoc(type);
  613. if (autoDoc == null) {
  614. autoDoc = String.Empty;
  615. } else {
  616. autoDoc += Environment.NewLine + Environment.NewLine;
  617. }
  618. // Simple generated helpbased on ctor, if available.
  619. ConstructorInfo[] cis = type.GetConstructors();
  620. foreach (ConstructorInfo ci in cis) {
  621. autoDoc += FixCtorDoc(type, DocBuilder.CreateAutoDoc(ci, DynamicHelpers.GetPythonTypeFromType(type).Name, 0)) + Environment.NewLine;
  622. }
  623. return autoDoc;
  624. }
  625. private static string FixCtorDoc(Type type, string autoDoc) {
  626. return autoDoc.Replace("__new__(cls)", DynamicHelpers.GetPythonTypeFromType(type).Name + "()").
  627. Replace("__new__(cls, ", DynamicHelpers.GetPythonTypeFromType(type).Name + "(");
  628. }
  629. internal static ReflectedGetterSetter GetReflectedProperty(PropertyTracker pt, MemberGroup allProperties, bool privateBinding) {
  630. ReflectedGetterSetter rp;
  631. lock (_propertyCache) {
  632. if (_propertyCache.TryGetValue(pt, out rp)) {
  633. return rp;
  634. }
  635. NameType nt = NameType.PythonProperty;
  636. MethodInfo getter = FilterProtectedGetterOrSetter(pt.GetGetMethod(true), privateBinding);
  637. MethodInfo setter = FilterProtectedGetterOrSetter(pt.GetSetMethod(true), privateBinding);
  638. if ((getter != null && getter.IsDefined(typeof(PythonHiddenAttribute), true)) ||
  639. setter != null && setter.IsDefined(typeof(PythonHiddenAttribute), true)) {
  640. nt = NameType.Property;
  641. }
  642. ExtensionPropertyTracker ept = pt as ExtensionPropertyTracker;
  643. if (ept == null) {
  644. ReflectedPropertyTracker rpt = pt as ReflectedPropertyTracker;
  645. Debug.Assert(rpt != null);
  646. if (PythonBinder.IsExtendedType(pt.DeclaringType) ||
  647. rpt.Property.IsDefined(typeof(PythonHiddenAttribute), true)) {
  648. nt = NameType.Property;
  649. }
  650. if (pt.GetIndexParameters().Length == 0) {
  651. List<MethodInfo> getters = new List<MethodInfo>();
  652. List<MethodInfo> setters = new List<MethodInfo>();
  653. IList<ExtensionPropertyTracker> overriddenProperties = NewTypeMaker.GetOverriddenProperties((getter ?? setter).DeclaringType, pt.Name);
  654. foreach (ExtensionPropertyTracker tracker in overriddenProperties) {
  655. MethodInfo method = tracker.GetGetMethod(privateBinding);
  656. if (method != null) {
  657. getters.Add(method);
  658. }
  659. method = tracker.GetSetMethod(privateBinding);
  660. if (method != null) {
  661. setters.Add(method);
  662. }
  663. }
  664. foreach (PropertyTracker propTracker in allProperties) {
  665. MethodInfo method = propTracker.GetGetMethod(privateBinding);
  666. if (method != null) {
  667. getters.Add(method);
  668. }
  669. method = propTracker.GetSetMethod(privateBinding);
  670. if (method != null) {
  671. setters.Add(method);
  672. }
  673. }
  674. rp = new ReflectedProperty(rpt.Property, getters.ToArray(), setters.ToArray(), nt);
  675. } else {
  676. rp = new ReflectedIndexer(((ReflectedPropertyTracker)pt).Property, NameType.Property, privateBinding);
  677. }
  678. } else {
  679. rp = new ReflectedExtensionProperty(new ExtensionPropertyInfo(pt.DeclaringType, getter ?? setter), nt);
  680. }
  681. _propertyCache[pt] = rp;
  682. return rp;
  683. }
  684. }
  685. private static MethodInfo FilterProtectedGetterOrSetter(MethodInfo info, bool privateBinding) {
  686. if (info != null) {
  687. if (privateBinding || info.IsPublic) {
  688. return info;
  689. }
  690. if (info.IsProtected()) {
  691. return info;
  692. }
  693. }
  694. return null;
  695. }
  696. internal static bool TryInvokeUnaryOperator(CodeContext context, object o, string name, out object value) {
  697. PerfTrack.NoteEvent(PerfTrack.Categories.Temporary, "UnaryOp " + CompilerHelpers.GetType(o).Name + " " + name);
  698. PythonTypeSlot pts;
  699. PythonType pt = DynamicHelpers.GetPythonType(o);
  700. object callable;
  701. if (pt.TryResolveMixedSlot(context, name, out pts) &&
  702. pts.TryGetValue(context, o, pt, out callable)) {
  703. value = PythonCalls.Call(context, callable);
  704. return true;
  705. }
  706. value = null;
  707. return false;
  708. }
  709. internal static bool TryInvokeBinaryOperator(CodeContext context, object o, object arg1, string name, out object value) {
  710. PerfTrack.NoteEvent(PerfTrack.Categories.Temporary, "BinaryOp " + CompilerHelpers.GetType(o).Name + " " + name);
  711. PythonTypeSlot pts;
  712. PythonType pt = DynamicHelpers.GetPythonType(o);
  713. object callable;
  714. if (pt.TryResolveMixedSlot(context, name, out pts) &&
  715. pts.TryGetValue(context, o, pt, out callable)) {
  716. value = PythonCalls.Call(context, callable, arg1);
  717. return true;
  718. }
  719. value = null;
  720. return false;
  721. }
  722. internal static bool TryInvokeTernaryOperator(CodeContext context, object o, object arg1, object arg2, string name, out object value) {
  723. PerfTrack.NoteEvent(PerfTrack.Categories.Temporary, "TernaryOp " + CompilerHelpers.GetType(o).Name + " " + name);
  724. PythonTypeSlot pts;
  725. PythonType pt = DynamicHelpers.GetPythonType(o);
  726. object callable;
  727. if (pt.TryResolveMixedSlot(context, name, out pts) &&
  728. pts.TryGetValue(context, o, pt, out callable)) {
  729. value = PythonCalls.Call(context, callable, arg1, arg2);
  730. return true;
  731. }
  732. value = null;
  733. return false;
  734. }
  735. /// <summary>
  736. /// If we have only interfaces, we'll need to insert object's base
  737. /// </summary>
  738. internal static PythonTuple EnsureBaseType(PythonTuple bases) {
  739. bool hasInterface = false;
  740. foreach (object baseClass in bases) {
  741. if (baseClass is OldClass) continue;
  742. PythonType dt = baseClass as PythonType;
  743. if (!dt.UnderlyingSystemType.IsInterface()) {
  744. return bases;
  745. } else {
  746. hasInterface = true;
  747. }
  748. }
  749. if (hasInterface || bases.Count == 0) {
  750. // We found only interfaces. We need do add System.Object to the bases
  751. return new PythonTuple(bases, TypeCache.Object);
  752. }
  753. throw PythonOps.TypeError("a new-style class can't have only classic bases");
  754. }
  755. internal static Type GetFinalSystemType(Type type) {
  756. while (typeof(IPythonObject).IsAssignableFrom(type) && !type.GetTypeInfo().IsDefined(typeof(DynamicBaseTypeAttribute), false)) {
  757. type = type.GetBaseType();
  758. }
  759. return type;
  760. }
  761. }
  762. }