PageRenderTime 41ms CodeModel.GetById 14ms RepoModel.GetById 0ms app.codeStats 1ms

/Python/Product/Analysis/SaveAnalysis.cs

https://gitlab.com/SplatoonModdingHub/PTVS
C# | 763 lines | 640 code | 90 blank | 33 comment | 192 complexity | e1a1b3d479874706ac4977f98ab9e49a MD5 | raw file
  1. // Python Tools for Visual Studio
  2. // Copyright(c) Microsoft Corporation
  3. // All rights reserved.
  4. //
  5. // Licensed under the Apache License, Version 2.0 (the License); you may not use
  6. // this file except in compliance with the License. You may obtain a copy of the
  7. // License at http://www.apache.org/licenses/LICENSE-2.0
  8. //
  9. // THIS CODE IS PROVIDED ON AN *AS IS* BASIS, WITHOUT WARRANTIES OR CONDITIONS
  10. // OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION ANY
  11. // IMPLIED WARRANTIES OR CONDITIONS OF TITLE, FITNESS FOR A PARTICULAR PURPOSE,
  12. // MERCHANTABLITY OR NON-INFRINGEMENT.
  13. //
  14. // See the Apache Version 2.0 License for specific language governing
  15. // permissions and limitations under the License.
  16. using System;
  17. using System.Collections.Generic;
  18. using System.Diagnostics;
  19. using System.IO;
  20. using System.Linq;
  21. using System.Threading;
  22. using Microsoft.PythonTools.Analysis.Values;
  23. using Microsoft.PythonTools.Infrastructure;
  24. using Microsoft.PythonTools.Intellisense;
  25. using Microsoft.PythonTools.Interpreter;
  26. using Microsoft.PythonTools.Parsing.Ast;
  27. namespace Microsoft.PythonTools.Analysis {
  28. class SaveAnalysis {
  29. private List<string> _errors = new List<string>();
  30. private Dictionary<AnalysisValue, string> _classNames = new Dictionary<AnalysisValue, string>();
  31. private List<AnalysisValue> _path = new List<AnalysisValue>();
  32. private Dictionary<string, Dictionary<string, object>> _typeNames = new Dictionary<string, Dictionary<string, object>>();
  33. private Dictionary<string, string> _MemoizedStrings = new Dictionary<string, string>();
  34. private Dictionary<string, object[]> _moduleNames = new Dictionary<string, object[]>();
  35. private static readonly List<object> _EmptyMro = new List<object>();
  36. private PythonAnalyzer _curAnalyzer;
  37. private ModuleInfo _curModule;
  38. public void Save(PythonAnalyzer state, string outDir) {
  39. _curAnalyzer = state;
  40. foreach (var modKeyValue in state.Modules) {
  41. string name = modKeyValue.Key;
  42. ModuleInfo moduleInfo;
  43. if ((moduleInfo = modKeyValue.Value.Module as ModuleInfo) != null) {
  44. _curModule = moduleInfo;
  45. var info = SerializeModule(moduleInfo);
  46. WriteModule(outDir, name, info, moduleInfo.Scope.AllVariables.Keys());
  47. }
  48. }
  49. foreach (var error in _errors) {
  50. Console.WriteLine(error);
  51. }
  52. }
  53. private void WriteModule(string outDir, string name, Dictionary<string, object> info, IEnumerable<string> globals) {
  54. for (int i = 0; i < 10; i++) {
  55. try {
  56. using (var writer = new FileStream(Path.Combine(outDir, name + ".idb"), FileMode.Create, FileAccess.ReadWrite)) {
  57. new Pickler(writer).Dump(info);
  58. }
  59. break;
  60. } catch (IOException ex) {
  61. // race with a reader, retry... http://pytools.codeplex.com/workitem/570
  62. Console.WriteLine("Could not access {0} {1}", name + ".idb", ex);
  63. Thread.Sleep(1000);
  64. }
  65. }
  66. for (int i = 0; i < 10; i++) {
  67. try {
  68. using (var writer = new StreamWriter(new FileStream(Path.Combine(outDir, name + ".idb.$memlist"), FileMode.Create, FileAccess.ReadWrite))) {
  69. object membersObj;
  70. Dictionary<string, object> members;
  71. if (!info.TryGetValue("members", out membersObj) ||
  72. (members = membersObj as Dictionary<string, object>) == null) {
  73. if (globals != null) {
  74. members = globals.ToDictionary(k => k, _ => (object)null);
  75. } else {
  76. members = new Dictionary<string, object>();
  77. }
  78. }
  79. foreach (var memberName in members.Keys) {
  80. writer.WriteLine(memberName);
  81. }
  82. }
  83. break;
  84. } catch (IOException ex) {
  85. // race with a reader, retry... http://pytools.codeplex.com/workitem/570
  86. Console.WriteLine("Could not access {0} {1}", name + ".idb.$memlist", ex);
  87. Thread.Sleep(1000);
  88. }
  89. }
  90. }
  91. private Dictionary<string, object> SerializeModule(ModuleInfo moduleInfo) {
  92. var children = GenerateChildModules(moduleInfo);
  93. return new Dictionary<string, object>() {
  94. { "members", GenerateMembers(moduleInfo, children) },
  95. { "doc", MemoizeString(moduleInfo.Documentation) },
  96. { "children", children },
  97. { "filename", moduleInfo.ProjectEntry.FilePath }
  98. };
  99. }
  100. private List<object> GenerateChildModules(ModuleInfo moduleInfo) {
  101. var res = new HashSet<object>(moduleInfo.GetChildrenPackages(null).Select(kv => kv.Key));
  102. // Add any child built-in modules as well. This will include the modules that are part of the package,
  103. // but which do not participate in analysis (e.g. native modules).
  104. foreach (var child in
  105. from moduleName in moduleInfo.ProjectEntry.ProjectState.Interpreter.GetModuleNames()
  106. let lastDot = moduleName.LastIndexOf('.')
  107. where lastDot >= 0
  108. let packageName = moduleName.Substring(0, lastDot)
  109. where packageName == moduleInfo.Name
  110. select moduleName.Substring(lastDot + 1)
  111. ) {
  112. // Only include the child if it is actually importable. As a
  113. // side-effect, we really import the child, which means that
  114. // GenerateMembers will not exclude it.
  115. ModuleReference modTableRef;
  116. if (moduleInfo.ProjectEntry.ProjectState.Modules.TryImport(moduleInfo.Name + "." + child, out modTableRef)) {
  117. res.Add(child);
  118. }
  119. }
  120. return res.ToList();
  121. }
  122. private Dictionary<string, object> GenerateMembers(ModuleInfo moduleInfo, IEnumerable<object> children) {
  123. Dictionary<string, object> res = new Dictionary<string, object>();
  124. foreach (var keyValue in moduleInfo.Scope.AllVariables) {
  125. if (keyValue.Value.IsEphemeral) {
  126. // Never got a value, so leave it out.
  127. continue;
  128. }
  129. res[keyValue.Key] = GenerateMember(keyValue.Value, moduleInfo);
  130. }
  131. foreach (var child in children.OfType<string>()) {
  132. object modRef = null;
  133. ModuleReference modTableRef;
  134. if (moduleInfo.ProjectEntry.ProjectState.Modules.TryGetImportedModule(moduleInfo.Name + "." + child, out modTableRef) &&
  135. modTableRef != null &&
  136. modTableRef.Module != null
  137. ) {
  138. MultipleMemberInfo mmi;
  139. if (modTableRef.Module is ModuleInfo || modTableRef.Module is BuiltinModule) {
  140. modRef = new Dictionary<string, object> {
  141. { "kind", "moduleref" },
  142. { "value", GetModuleName(moduleInfo.Name + "." + child) }
  143. };
  144. } else if ((mmi = modTableRef.Module as MultipleMemberInfo) != null) {
  145. modRef = new Dictionary<string, object> {
  146. { "kind", "multiple" },
  147. { "value", new Dictionary<string, object> {
  148. {
  149. "members",
  150. mmi.Members
  151. .Select(m => m.Name)
  152. .Where(n => !string.IsNullOrEmpty(n))
  153. .Select(GetModuleName)
  154. .ToArray<object>()
  155. }
  156. } }
  157. };
  158. }
  159. }
  160. object existing;
  161. if (res.TryGetValue(child, out existing) && IsValidMember(existing)) {
  162. var members1 = GetMultipleMembersOrDefault(existing) ?? new object[] { existing };
  163. var members2 = GetMultipleMembersOrDefault(modRef) ?? new object[] { modRef };
  164. var members = members1.Concat(members2).Distinct(ModuleReferenceComparer.Instance).ToArray();
  165. if (members.Length > 1) {
  166. res[child] = new Dictionary<string, object> {
  167. { "kind", "multiple" },
  168. { "value", new Dictionary<string, object> { { "members", members } } }
  169. };
  170. } else if (members.Length == 1) {
  171. res[child] = members[0];
  172. }
  173. } else {
  174. res[child] = modRef;
  175. }
  176. }
  177. return res;
  178. }
  179. private class ModuleReferenceComparer : IEqualityComparer<object> {
  180. public static readonly IEqualityComparer<object> Instance = new ModuleReferenceComparer();
  181. private ModuleReferenceComparer() { }
  182. public new bool Equals(object x, object y) {
  183. if (object.ReferenceEquals(x, y)) {
  184. return true;
  185. }
  186. var asDict1 = x as Dictionary<string, object>;
  187. var asDict2 = y as Dictionary<string, object>;
  188. if (asDict1 == null || asDict2 == null) {
  189. return false;
  190. }
  191. object obj;
  192. if (!asDict1.TryGetValue("kind", out obj) || (obj as string) != "moduleref") {
  193. return false;
  194. }
  195. if (!asDict2.TryGetValue("kind", out obj) || (obj as string) != "moduleref") {
  196. return false;
  197. }
  198. object[] modref1, modref2;
  199. if (!asDict1.TryGetValue("value", out obj) || (modref1 = obj as object[]) == null) {
  200. return false;
  201. }
  202. if (!asDict2.TryGetValue("value", out obj) || (modref2 = obj as object[]) == null) {
  203. return false;
  204. }
  205. return modref1.SequenceEqual(modref2);
  206. }
  207. public int GetHashCode(object obj) {
  208. var asDict = obj as Dictionary<string, object>;
  209. if (asDict == null) {
  210. return 0;
  211. }
  212. object o;
  213. if (!asDict.TryGetValue("kind", out o) || (o as string) != "moduleref") {
  214. return 0;
  215. }
  216. object[] modref;
  217. if (!asDict.TryGetValue("value", out o) || (modref = o as object[]) == null) {
  218. return 0;
  219. }
  220. return modref.Aggregate(48527, (a, n) => a ^ (n != null ? n.GetHashCode() : 0));
  221. }
  222. }
  223. private static bool IsValidMember(object info) {
  224. var asDict = info as Dictionary<string, object>;
  225. if (asDict == null) {
  226. return false;
  227. }
  228. object obj;
  229. string kind;
  230. if (!asDict.TryGetValue("kind", out obj) || (kind = obj as string) == null) {
  231. return false;
  232. }
  233. if (!asDict.TryGetValue("value", out obj)) {
  234. return false;
  235. }
  236. if (kind == "data" && (asDict = obj as Dictionary<string, object>) != null) {
  237. // { 'data': { 'type': None } } is invalid
  238. return asDict.TryGetValue("type", out obj) && obj != null;
  239. }
  240. return true;
  241. }
  242. private static object[] GetMultipleMembersOrDefault(object info) {
  243. var asDict = info as Dictionary<string, object>;
  244. if (asDict == null) {
  245. return null;
  246. }
  247. object obj;
  248. string kind;
  249. if (!asDict.TryGetValue("kind", out obj) || (kind = obj as string) == null || kind != "multiple") {
  250. return null;
  251. }
  252. if (!asDict.TryGetValue("value", out obj) || (asDict = obj as Dictionary<string, object>) == null) {
  253. return null;
  254. }
  255. if (!asDict.TryGetValue("members", out obj)) {
  256. return null;
  257. }
  258. return obj as object[];
  259. }
  260. private object GenerateMember(VariableDef variableDef, ModuleInfo declModule, bool isRef = false) {
  261. Dictionary<string, object> memberEntry = new Dictionary<string, object>() {
  262. { "kind", GetMemberKind(variableDef, declModule, isRef) },
  263. { "value", GetMemberValue(variableDef, declModule, isRef) }
  264. };
  265. return memberEntry;
  266. }
  267. private object GetMemberValues(VariableDef[] variableDefs, ModuleInfo declModule, bool isRef) {
  268. List<object> res = new List<object>();
  269. foreach (var variableDef in variableDefs) {
  270. res.Add(GetMemberValue(variableDef, declModule, isRef));
  271. }
  272. return res;
  273. }
  274. private object GetMemberValue(VariableDef variableDef, ModuleInfo declModule, bool isRef) {
  275. return GetMemberValue(variableDef.TypesNoCopy, declModule, isRef);
  276. }
  277. private object GetMemberValue(IAnalysisSet types, ModuleInfo declModule, bool isRef) {
  278. if (types.Count == 1) {
  279. var type = types.First();
  280. var res = GetMemberValueInternal(type, declModule, isRef);
  281. if (res == null) {
  282. _errors.Add(String.Format("Cannot save single member: {0}", types.First()));
  283. }
  284. return res;
  285. } else if (types.Count == 0) {
  286. return new Dictionary<string, object>() {
  287. { "type", null }
  288. };
  289. } else {
  290. List<object> res = new List<object>();
  291. foreach (var type in types) {
  292. res.Add(
  293. new Dictionary<string, object>() {
  294. { "kind", GetMemberKind(type, declModule, isRef) },
  295. { "value", GetMemberValueInternal(type, declModule, isRef) }
  296. }
  297. );
  298. }
  299. return new Dictionary<string, object>() {
  300. { "members", res.ToArray() }
  301. };
  302. }
  303. }
  304. private object GetMemberValueInternal(AnalysisValue type, ModuleInfo declModule, bool isRef) {
  305. SpecializedNamespace specialCallable = type as SpecializedNamespace;
  306. if (specialCallable != null) {
  307. if (specialCallable.Original == null) {
  308. return null;
  309. }
  310. return GetMemberValueInternal(specialCallable.Original, declModule, isRef);
  311. }
  312. switch (type.MemberType) {
  313. case PythonMemberType.Function:
  314. FunctionInfo fi = type as FunctionInfo;
  315. if (fi != null) {
  316. if (fi.DeclaringModule.GetModuleInfo() != declModule) {
  317. return GenerateFuncRef(fi);
  318. } else {
  319. return GenerateFunction(fi);
  320. }
  321. }
  322. BuiltinFunctionInfo bfi = type as BuiltinFunctionInfo;
  323. if (bfi != null) {
  324. return GenerateFuncRef(bfi);
  325. }
  326. return "function";
  327. case PythonMemberType.Method:
  328. BoundMethodInfo mi = type as BoundMethodInfo;
  329. if (mi != null) {
  330. return GenerateMethod(mi);
  331. }
  332. return "method";
  333. case PythonMemberType.Property:
  334. FunctionInfo prop = type as FunctionInfo;
  335. if (prop != null) {
  336. return GenerateProperty(prop);
  337. }
  338. break;
  339. case PythonMemberType.Class:
  340. ClassInfo ci = type as ClassInfo;
  341. if (ci != null) {
  342. if (isRef || ci.DeclaringModule.GetModuleInfo() != declModule) {
  343. // TODO: Save qualified name so that classes defined in classes/function can be resolved
  344. return GetTypeRef(ci.DeclaringModule.ModuleName, ci.Name);
  345. } else {
  346. return GenerateClass(ci, declModule);
  347. }
  348. }
  349. BuiltinClassInfo bci = type as BuiltinClassInfo;
  350. if (bci != null) {
  351. return GetTypeRef(bci.PythonType.DeclaringModule.Name, bci.PythonType.Name);
  352. }
  353. return "type";
  354. case PythonMemberType.Constant:
  355. ConstantInfo constantInfo = type as ConstantInfo;
  356. if (constantInfo != null) {
  357. return GenerateConstant(constantInfo);
  358. }
  359. break;
  360. case PythonMemberType.Module:
  361. if (type is ModuleInfo) {
  362. return GetModuleName(((ModuleInfo)type).Name);
  363. } else if (type is BuiltinModule) {
  364. return GetModuleName(((BuiltinModule)type).Name);
  365. }
  366. break;
  367. case PythonMemberType.Instance:
  368. return new Dictionary<string, object> {
  369. { "type", GenerateTypeName(type, true) }
  370. };
  371. default:
  372. return new Dictionary<string, object>() {
  373. { "type", GenerateTypeName(type.PythonType) }
  374. };
  375. }
  376. return null;
  377. }
  378. private object GenerateFuncRef(FunctionInfo fi) {
  379. string name = ".";
  380. for (var cd = fi.FunctionDefinition.Parent as ClassDefinition;
  381. cd != null;
  382. cd = cd.Parent as ClassDefinition) {
  383. name = "." + cd.Name + name;
  384. }
  385. name = fi.DeclaringModule.ModuleName + name + fi.Name;
  386. return new Dictionary<string, object>() {
  387. { "func_name", MemoizeString(name) }
  388. };
  389. }
  390. private object GenerateFuncRef(BuiltinFunctionInfo bfi) {
  391. string name = bfi.Function.DeclaringModule.Name;
  392. if (bfi.Function.DeclaringType != null) {
  393. name += "." + bfi.Function.DeclaringType.Name;
  394. }
  395. name += "." + bfi.Function.Name;
  396. return new Dictionary<string, object>() {
  397. { "func_name", MemoizeString(name) }
  398. };
  399. }
  400. private string GetMemberKind(VariableDef variableDef, ModuleInfo declModule, bool isRef) {
  401. if (variableDef.Types.Count == 1) {
  402. return GetMemberKind(variableDef.Types.First(), declModule, isRef);
  403. } else if (variableDef.Types.Count == 0) {
  404. // typed to object
  405. return "data";
  406. } else {
  407. return "multiple";
  408. }
  409. }
  410. private static string GetMemberKind(AnalysisValue type, ModuleInfo declModule, bool isRef) {
  411. SpecializedNamespace specialCallable = type as SpecializedNamespace;
  412. if (specialCallable != null) {
  413. if (specialCallable.Original == null) {
  414. return "data";
  415. }
  416. return GetMemberKind(specialCallable.Original, declModule, isRef);
  417. }
  418. switch (type.MemberType) {
  419. case PythonMemberType.Function:
  420. if (type is BuiltinFunctionInfo || type.DeclaringModule != declModule.ProjectEntry) {
  421. return "funcref";
  422. }
  423. return "function";
  424. case PythonMemberType.Method: return "method";
  425. case PythonMemberType.Property: return "property";
  426. case PythonMemberType.Class:
  427. if (isRef || type is BuiltinClassInfo || (type is ClassInfo && type.DeclaringModule.GetModuleInfo() != declModule)) {
  428. return "typeref";
  429. }
  430. return "type";
  431. case PythonMemberType.Module:
  432. return "moduleref";
  433. case PythonMemberType.Instance:
  434. default:
  435. return "data";
  436. }
  437. }
  438. private object GenerateProperty(FunctionInfo prop) {
  439. return new Dictionary<string, object>() {
  440. { "doc", MemoizeString(prop.Documentation) },
  441. { "type", GenerateTypeName(GetFunctionReturnTypes(prop), true) },
  442. { "location", GenerateLocation(prop.Locations) }
  443. };
  444. }
  445. private static IAnalysisSet GetFunctionReturnTypes(FunctionInfo func) {
  446. return func.GetReturnValue();
  447. }
  448. private Dictionary<string, object> GenerateConstant(ConstantInfo constantInfo) {
  449. return new Dictionary<string, object>() {
  450. { "type", GenerateTypeName(constantInfo.PythonType) }
  451. };
  452. }
  453. private Dictionary<string, object> GenerateClass(ClassInfo ci, ModuleInfo declModule) {
  454. return new Dictionary<string, object>() {
  455. { "mro", GetClassMro(ci) },
  456. { "bases", GetClassBases(ci) },
  457. { "members", GetClassMembers(ci, declModule) },
  458. { "doc", MemoizeString(ci.Documentation) },
  459. { "builtin", false },
  460. { "location", GenerateLocation(ci.Locations) }
  461. };
  462. }
  463. private object GetTypeRef(string moduleName, string className) {
  464. return new List<object> { GetTypeName(moduleName, className) };
  465. }
  466. private object GetTypeName(string moduleName, string className) {
  467. // memoize types names for a more efficient on disk representation.
  468. object typeName;
  469. Dictionary<string, object> typeNames;
  470. if (!_typeNames.TryGetValue(moduleName, out typeNames)) {
  471. _typeNames[moduleName] = typeNames = new Dictionary<string, object>();
  472. }
  473. if (!typeNames.TryGetValue(className, out typeName)) {
  474. typeNames[className] = typeName = new object[] {
  475. MemoizeString(moduleName),
  476. MemoizeString(className)
  477. };
  478. }
  479. return typeName;
  480. }
  481. private object[] GetModuleName(string moduleName) {
  482. // memoize types names for a more efficient on disk representation.
  483. object[] name;
  484. if (!_moduleNames.TryGetValue(moduleName, out name)) {
  485. _moduleNames[moduleName] = name = new object[] { MemoizeString(moduleName), string.Empty };
  486. }
  487. return name;
  488. }
  489. private object GetClassMembers(ClassInfo ci, ModuleInfo declModule) {
  490. Dictionary<string, object> memTable = new Dictionary<string, object>();
  491. foreach (var keyValue in ci.Scope.AllVariables) {
  492. if (keyValue.Value.IsEphemeral) {
  493. continue;
  494. }
  495. memTable[keyValue.Key] = GenerateMember(keyValue.Value, declModule, true);
  496. }
  497. if (ci.Instance.InstanceAttributes != null) {
  498. foreach (var keyValue in ci.Instance.InstanceAttributes) {
  499. if (keyValue.Value.IsEphemeral) {
  500. continue;
  501. }
  502. memTable[keyValue.Key] = GenerateMember(keyValue.Value, declModule, true);
  503. }
  504. }
  505. return memTable;
  506. }
  507. private List<object> GetClassBases(ClassInfo ci) {
  508. List<object> res = new List<object>();
  509. foreach (var baseClassSet in ci.Bases) {
  510. foreach (var baseClass in baseClassSet) {
  511. var typeName = GenerateTypeName(baseClass, true);
  512. if (typeName != null) {
  513. res.Add(typeName);
  514. }
  515. }
  516. }
  517. return res;
  518. }
  519. private object GenerateTypeName(IAnalysisSet name, bool isRef) {
  520. if (name.Count == 0) {
  521. return null;
  522. } else if (name.Count == 1) {
  523. return GenerateTypeName(name.First(), isRef);
  524. }
  525. return name.Select(ns => GenerateTypeName(ns, isRef)).Distinct().ToList<object>();
  526. }
  527. private object GenerateTypeName(AnalysisValue baseClass, bool isRef) {
  528. ClassInfo ci = baseClass as ClassInfo;
  529. if (ci != null) {
  530. return GetTypeName(((ProjectEntry)ci.DeclaringModule).GetModuleInfo().Name, ci.ClassDefinition.Name);
  531. }
  532. BuiltinClassInfo bci = baseClass as BuiltinClassInfo;
  533. if (bci != null) {
  534. return GenerateTypeName(bci._type);
  535. }
  536. IterableValue iteri = baseClass as IterableValue;
  537. if (iteri != null) {
  538. return GenerateTypeName(iteri.PythonType, isRef, iteri.IndexTypes);
  539. }
  540. InstanceInfo ii = baseClass as InstanceInfo;
  541. if (ii != null) {
  542. return GenerateTypeName(ii.ClassInfo, isRef);
  543. }
  544. BuiltinInstanceInfo bii = baseClass as BuiltinInstanceInfo;
  545. if (bii != null) {
  546. return GenerateTypeName(bii.ClassInfo, isRef);
  547. }
  548. return GenerateTypeName(baseClass.PythonType);
  549. }
  550. private object GenerateTypeName(IPythonType type) {
  551. if (type != null) {
  552. return GetTypeName(type.DeclaringModule.Name, type.Name);
  553. }
  554. return null;
  555. }
  556. private object GenerateTypeName(IPythonType type, bool isRef, VariableDef[] indexTypes) {
  557. if (type != null) {
  558. if (indexTypes == null || indexTypes.Length == 0) {
  559. return GetTypeName(type.DeclaringModule.Name, type.Name);
  560. }
  561. var moduleName = type.DeclaringModule.Name;
  562. var className = type.Name + "`" + string.Join(",", indexTypes.Select(t => t.TypesNoCopy.ToString()));
  563. object typeName;
  564. Dictionary<string, object> typeNames;
  565. if (!_typeNames.TryGetValue(moduleName, out typeNames)) {
  566. _typeNames[moduleName] = typeNames = new Dictionary<string, object>();
  567. }
  568. if (!typeNames.TryGetValue(className, out typeName)) {
  569. var mModuleName = MemoizeString(moduleName);
  570. var mTypeName = MemoizeString(type.Name);
  571. // Create a type without the typename that will be used if
  572. // the index types recurse.
  573. typeNames[className] = typeName = new object[] { mModuleName, mTypeName };
  574. typeNames[className] = typeName = new object[] {
  575. mModuleName,
  576. mTypeName,
  577. indexTypes.Select(vd => GenerateTypeName(vd.TypesNoCopy, isRef)).ToList<object>(),
  578. };
  579. }
  580. return typeName;
  581. }
  582. return null;
  583. }
  584. private object GetClassMro(ClassInfo ci) {
  585. List<object> res = new List<object>();
  586. foreach (var mroClassSet in ci.Mro) {
  587. foreach (var mroClass in mroClassSet) {
  588. var typeName = GenerateTypeName(mroClass, true);
  589. if (typeName != null) {
  590. res.Add(typeName);
  591. }
  592. }
  593. }
  594. return res;
  595. }
  596. private Dictionary<string, object> GenerateFunction(FunctionInfo fi) {
  597. // TODO: Include inner classes/functions
  598. var res = new Dictionary<string, object>() {
  599. { "doc", fi.Documentation },
  600. { "builtin", false },
  601. { "location", GenerateLocation(fi.Locations) },
  602. { "overloads", GenerateOverloads(fi) }
  603. };
  604. if (fi.IsStatic) {
  605. res["static"] = fi.IsStatic;
  606. }
  607. if (fi.IsClassMethod) {
  608. res["classmethod"] = true;
  609. }
  610. return res;
  611. }
  612. private Dictionary<string, object> GenerateMethod(BoundMethodInfo bmi) {
  613. var res = GenerateFunction(bmi.Function);
  614. if (bmi.Instance != null && bmi.Instance.TypeId != BuiltinTypeId.NoneType) {
  615. res["bound"] = true;
  616. }
  617. return res;
  618. }
  619. private static object[] GenerateLocation(LocationInfo location) {
  620. return new object[] { location.StartLine, location.StartColumn };
  621. }
  622. private static object[] GenerateLocation(IEnumerable<LocationInfo> locations) {
  623. // TODO: Support saving and loading multiple locations for a single definition
  624. Debug.Assert(locations.Count() == 1);
  625. var location = locations.FirstOrDefault();
  626. if (location != null) {
  627. return GenerateLocation(location);
  628. }
  629. return new object[0];
  630. }
  631. private List<object> GenerateOverloads(FunctionInfo fi) {
  632. var res = new List<object>();
  633. // TODO: Store distinct calls as separate overloads
  634. res.Add(new Dictionary<string, object> {
  635. { "args", GenerateArgInfo(fi, fi.GetParameterTypes()) },
  636. { "ret_type", GenerateTypeName(fi.GetReturnValue(), true) }
  637. });
  638. return res;
  639. }
  640. private object[] GenerateArgInfo(FunctionInfo fi, IAnalysisSet[] parameters) {
  641. var res = new object[Math.Min(fi.FunctionDefinition.Parameters.Count, parameters.Length)];
  642. for (int i = 0; i < res.Length; i++) {
  643. res[i] = GenerateParameter(fi.FunctionDefinition.Parameters[i], parameters[i]);
  644. }
  645. return res;
  646. }
  647. private string MemoizeString(string input) {
  648. if (input == null) {
  649. return null;
  650. }
  651. string res;
  652. if (!_MemoizedStrings.TryGetValue(input, out res)) {
  653. _MemoizedStrings[input] = res = input;
  654. }
  655. return res;
  656. }
  657. private object GenerateParameter(Parameter param, IAnalysisSet typeInfo) {
  658. Dictionary<string, object> res = new Dictionary<string, object>();
  659. if (param.Kind == ParameterKind.Dictionary) {
  660. res["arg_format"] = "**";
  661. } else if (param.Kind == ParameterKind.List) {
  662. res["arg_format"] = "*";
  663. }
  664. res["name"] = MemoizeString(param.Name);
  665. res["type"] = GenerateTypeName(typeInfo, true);
  666. var defaultValue = FunctionInfo.GetDefaultValue(_curAnalyzer, param, _curModule.ProjectEntry.Tree);
  667. if (defaultValue != null) {
  668. res["default_value"] = defaultValue;
  669. }
  670. return res;
  671. }
  672. }
  673. }