PageRenderTime 30ms CodeModel.GetById 27ms RepoModel.GetById 0ms app.codeStats 1ms

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

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