PageRenderTime 58ms CodeModel.GetById 24ms RepoModel.GetById 0ms app.codeStats 0ms

/DICK.B1/IronPython/Runtime/Operations/PythonTypeOps.cs

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