PageRenderTime 58ms CodeModel.GetById 25ms RepoModel.GetById 1ms app.codeStats 0ms

/Tools/IronStudio/IronPythonToolsCore/PyAnalysis/Interpreter/DDG.cs

http://github.com/IronLanguages/main
C# | 670 lines | 527 code | 95 blank | 48 comment | 159 complexity | 7a8f327626a5fef16bab9b6d4e3ee6e4 MD5 | raw file
Possible License(s): CPL-1.0, BSD-3-Clause, ISC, GPL-2.0, MPL-2.0-no-copyleft-exception
  1. /* ****************************************************************************
  2. *
  3. * Copyright (c) Microsoft Corporation.
  4. *
  5. * This source code is subject to terms and conditions of the Apache License, Version 2.0. A
  6. * copy of the license can be found in the License.html file at the root of this distribution. If
  7. * you cannot locate the Apache License, Version 2.0, please send an email to
  8. * ironpy@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. using System;
  15. using System.Collections.Generic;
  16. using System.Diagnostics;
  17. using System.Linq;
  18. using IronPython.Compiler.Ast;
  19. using Microsoft.PyAnalysis.Values;
  20. namespace Microsoft.PyAnalysis.Interpreter {
  21. internal class DDG : PythonWalker {
  22. private AnalysisUnit _unit;
  23. private ExpressionEvaluator _eval;
  24. public void Analyze(Queue<AnalysisUnit>queue) {
  25. while (queue.Count > 0) {
  26. _unit = queue.Dequeue();
  27. _unit.IsInQueue = false;
  28. _eval = new ExpressionEvaluator(_unit);
  29. _unit.Ast.Walk(this);
  30. }
  31. }
  32. public InterpreterScope[] Scopes {
  33. get { return _unit.Scopes; }
  34. }
  35. public ModuleInfo GlobalScope {
  36. get { return _unit.DeclaringModule; }
  37. }
  38. public ProjectState ProjectState {
  39. get { return _unit.ProjectState; }
  40. }
  41. public override bool Walk(PythonAst node) {
  42. ModuleReference existingRef;
  43. Debug.Assert(node == _unit.Ast);
  44. if (ProjectState.Modules.TryGetValue(_unit.DeclaringModule.Name, out existingRef)) {
  45. // if we have dependencies from files which were processed before us
  46. // we need to re-enqueue those files.
  47. if (existingRef.References != null) {
  48. foreach (var referer in existingRef.References) {
  49. referer.Enqueue();
  50. }
  51. // we won't need to process these again, we'll track all of our future dependencies
  52. // via VariableDef's.
  53. existingRef.References = null;
  54. }
  55. } else {
  56. // publish our module ref now so that we don't collect dependencies as we'll be fully processed
  57. ProjectState.Modules[_unit.DeclaringModule.Name] = new ModuleReference(_unit.DeclaringModule);
  58. }
  59. return base.Walk(node);
  60. }
  61. /// <summary>
  62. /// Gets the function which we are processing code for currently or
  63. /// null if we are not inside of a function body.
  64. /// </summary>
  65. public FunctionScope CurrentFunction {
  66. get { return CurrentContainer<FunctionScope>(); }
  67. }
  68. public ClassScope CurrentClass {
  69. get { return CurrentContainer<ClassScope>(); }
  70. }
  71. private T CurrentContainer<T>() where T : InterpreterScope {
  72. for (int i = Scopes.Length - 1; i >= 0; i--) {
  73. T result = Scopes[i] as T;
  74. if (result != null) {
  75. return result;
  76. }
  77. }
  78. return null;
  79. }
  80. public T LookupDefinition<T>(Node node, string name) where T : Namespace {
  81. var defined = _eval.LookupNamespaceByName(node, name, false);
  82. foreach (var definition in defined) {
  83. T result = definition as T;
  84. if (result != null) {
  85. return result;
  86. }
  87. }
  88. return null;
  89. }
  90. private void AssignTo(Node assignStmt, Expression left, ISet<Namespace> values) {
  91. if (left is NameExpression) {
  92. var l = (NameExpression)left;
  93. var vars = _eval.LookupVariableByName(l.Name, l, false);
  94. if (vars == null) {
  95. vars = Scopes[Scopes.Length - 1].CreateVariable(left, _unit, l.Name, false);
  96. }
  97. vars.AddAssignment(left, _unit);
  98. vars.AddTypes(l, _unit, values);
  99. } else if (left is MemberExpression) {
  100. var l = (MemberExpression)left;
  101. foreach (var obj in _eval.Evaluate(l.Target)) {
  102. obj.SetMember(assignStmt, _unit, l.Name, values);
  103. }
  104. } else if (left is IndexExpression) {
  105. var l = (IndexExpression)left;
  106. var indexObj = _eval.Evaluate(l.Index);
  107. foreach (var obj in _eval.Evaluate(l.Target)) {
  108. obj.SetIndex(assignStmt, _unit, indexObj, values);
  109. }
  110. } else if (left is SequenceExpression) {
  111. // list/tuple
  112. var l = (SequenceExpression)left;
  113. foreach (var value in values.ToArray()) {
  114. for (int i = 0; i < l.Items.Count; i++) {
  115. AssignTo(assignStmt, l.Items[i], value.GetIndex(assignStmt, _unit, ProjectState.GetConstant(i)));
  116. }
  117. }
  118. }
  119. }
  120. public override bool Walk(AssignmentStatement node) {
  121. var valueType = _eval.Evaluate(node.Right);
  122. foreach (var left in node.Left) {
  123. AssignTo(node, left, valueType);
  124. }
  125. return false;
  126. }
  127. public override bool Walk(AugmentedAssignStatement node) {
  128. var right = _eval.Evaluate(node.Right);
  129. foreach (var x in _eval.Evaluate(node.Left)) {
  130. x.AugmentAssign(node, _unit, right);
  131. }
  132. return false;
  133. }
  134. public override bool Walk(ClassDefinition node) {
  135. if (node.Body == null || node.Name == null) {
  136. // invalid class body
  137. return false;
  138. }
  139. var newScope = LookupDefinition<ClassInfo>(node, node.Name);
  140. if (newScope == null) {
  141. // We failed to find the value, this occurs when there are multiple
  142. // definitions by the same name. For example:
  143. // class f:
  144. // def g(): pass
  145. // def f(): pass
  146. //
  147. // the 2nd f() will replace the first and we can't find g.
  148. return false;
  149. }
  150. newScope.Bases.Clear();
  151. // Process base classes
  152. foreach (var baseClass in node.Bases) {
  153. baseClass.Walk(this);
  154. var bases = _eval.Evaluate(baseClass);
  155. newScope.Bases.Add(bases);
  156. }
  157. WalkBody(node.Body, newScope._analysisUnit);
  158. return false;
  159. }
  160. public AnalysisUnit PushScope(AnalysisUnit unit) {
  161. var oldUnit = _unit;
  162. _unit = unit;
  163. return oldUnit;
  164. }
  165. public void PopScope(AnalysisUnit unit) {
  166. _unit = unit;
  167. }
  168. public override bool Walk(ExpressionStatement node) {
  169. _eval.Evaluate(node.Expression);
  170. return false;
  171. }
  172. public override bool Walk(ForStatement node) {
  173. foreach (var listType in _eval.Evaluate(node.List).ToArray()) {
  174. AssignTo(node, node.Left, listType.GetEnumeratorTypes(node, _unit));
  175. }
  176. if (node.Body != null) {
  177. node.Body.Walk(this);
  178. }
  179. if (node.Else != null) {
  180. node.Else.Walk(this);
  181. }
  182. return false;
  183. }
  184. private void WalkFromImportWorker(FromImportStatement node, Namespace userMod, object[] mods, string impName, string newName) {
  185. var saveName = (newName == null) ? impName : newName;
  186. GlobalScope.Imports[node].Types.Add(new[] { impName, newName });
  187. // TODO: Better node would be the name node but we don't have a name node (they're just strings in the AST w/ no position info)
  188. var variable = Scopes[Scopes.Length - 1].CreateVariable(node, _unit, saveName);
  189. ISet<Namespace> newTypes = EmptySet<Namespace>.Instance;
  190. bool madeSet = false;
  191. // look for builtin / user-defined modules first
  192. ModuleInfo module = userMod as ModuleInfo;
  193. if (module != null) {
  194. var modVal = module.Scope.CreateVariable(node, _unit, impName);
  195. modVal.AddDependency(_unit);
  196. newTypes = newTypes.Union(modVal.Types, ref madeSet);
  197. }
  198. BuiltinModule builtinModule = userMod as BuiltinModule;
  199. if (builtinModule != null) {
  200. var modVal = builtinModule.GetMember(node, _unit, impName);
  201. newTypes = newTypes.Union(modVal, ref madeSet);
  202. }
  203. // then look for .NET reflected namespace
  204. if (mods != null) {
  205. var mems = new List<object>(mods.Length);
  206. foreach (var mod in mods) {
  207. object val;
  208. if (ProjectState.TryGetMember(mod, impName, out val) && val != null) {
  209. mems.Add(val);
  210. }
  211. }
  212. if (mems.Count > 0) {
  213. GlobalScope.ShowClr = true;
  214. var ns = ProjectState.GetNamespaceFromObjects(mems);
  215. newTypes = newTypes.Union(ns.SelfSet, ref madeSet);
  216. }
  217. }
  218. variable.AddTypes(node, _unit, newTypes);
  219. }
  220. public override bool Walk(FromImportStatement node) {
  221. var mods = ProjectState.GetReflectedNamespaces(node.Root.Names, true);
  222. ModuleReference moduleRef;
  223. Namespace userMod = null;
  224. var modName = node.Root.MakeString();
  225. if (ProjectState.Modules.TryGetValue(modName, out moduleRef)) {
  226. userMod = moduleRef.Module;
  227. if (userMod == null) {
  228. moduleRef.References.Add(_unit);
  229. }
  230. } else {
  231. moduleRef = ProjectState.Modules[modName] = new ModuleReference();
  232. if (moduleRef.References == null) {
  233. moduleRef.References = new HashSet<AnalysisUnit>();
  234. }
  235. moduleRef.References.Add(_unit);
  236. }
  237. var asNames = node.AsNames ?? node.Names;
  238. var impInfo = new ImportInfo(node.Root.MakeString(), node.Span);
  239. GlobalScope.Imports[node] = impInfo;
  240. int len = Math.Min(node.Names.Count, asNames.Count);
  241. for (int i = 0; i < len; i++) {
  242. var impName = node.Names[i];
  243. var newName = asNames[i];
  244. if (impName == null) {
  245. // incomplete import statement
  246. continue;
  247. } else if (impName == "*") {
  248. // Handle "import *"
  249. if (userMod != null) {
  250. foreach (var varName in GetModuleKeys(userMod)) {
  251. WalkFromImportWorker(node, userMod, mods, varName, null);
  252. }
  253. }
  254. if (mods != null) {
  255. foreach (var mod in mods) {
  256. foreach (var name in Utils.DirHelper(mod, true)) {
  257. WalkFromImportWorker(node, null, mods, name, null);
  258. }
  259. }
  260. }
  261. } else {
  262. WalkFromImportWorker(node, userMod, mods, impName, newName);
  263. }
  264. }
  265. return true;
  266. }
  267. private ICollection<string> GetModuleKeys(Namespace userMod) {
  268. ModuleInfo mi = userMod as ModuleInfo;
  269. if (mi != null) {
  270. return mi.Scope.Variables.Keys;
  271. }
  272. BuiltinModule bmi = userMod as BuiltinModule;
  273. if (bmi != null) {
  274. return bmi.VariableDict.Keys;
  275. }
  276. return new string[0];
  277. }
  278. private List<Namespace> LookupBaseMethods(string name, IEnumerable<ISet<Namespace>> bases, Node node, AnalysisUnit unit) {
  279. var result = new List<Namespace>();
  280. foreach (var b in bases) {
  281. foreach (var curType in b) {
  282. BuiltinClassInfo klass = curType as BuiltinClassInfo;
  283. if (klass != null) {
  284. var value = klass.GetMember(node, unit, "name"); // curType.GetVariable(name);
  285. if (value != null) {
  286. result.AddRange(value);
  287. }
  288. }
  289. }
  290. }
  291. return result;
  292. }
  293. private void PropagateBaseParams(FunctionInfo newScope, Namespace method) {
  294. foreach (var overload in method.Overloads) {
  295. var p = overload.Parameters;
  296. if (p.Length == newScope.ParameterTypes.Length) {
  297. for (int i = 1; i < p.Length; i++) {
  298. var baseParam = p[i];
  299. var newParam = newScope.ParameterTypes[i];
  300. // TODO: baseParam.Type isn't right, it's a string, not a type object
  301. var baseType = ProjectState.GetNamespaceFromObjects(baseParam.Type);
  302. if (baseType != null) {
  303. newParam.Types.Add(baseType);
  304. }
  305. }
  306. }
  307. }
  308. }
  309. private void ProcessFunctionDecorators(FunctionDefinition funcdef, FunctionInfo newScope) {
  310. if (funcdef.Decorators != null) {
  311. foreach (var d in funcdef.Decorators) {
  312. var decorator = _eval.Evaluate(d);
  313. if (decorator.Contains(ProjectState._propertyObj)) {
  314. newScope.IsProperty = true;
  315. } else if (decorator.Contains(ProjectState._staticmethodObj)) {
  316. newScope.IsStatic = true;
  317. } else if (decorator.Contains(ProjectState._classmethodObj)) {
  318. newScope.IsClassMethod = true;
  319. }
  320. }
  321. }
  322. if (newScope.IsClassMethod) {
  323. if (newScope.ParameterTypes.Length > 0) {
  324. newScope.ParameterTypes[0].AddTypes(funcdef.Parameters[0], _unit, ProjectState._typeObj.SelfSet);
  325. }
  326. } else if (!newScope.IsStatic) {
  327. // self is always an instance of the class
  328. // TODO: Check for __new__ (auto static) and
  329. // @staticmethod and @classmethod and @property
  330. InstanceInfo selfInst = null;
  331. for (int i = Scopes.Length - 1; i >= 0; i--) {
  332. if (Scopes[i] is ClassScope) {
  333. selfInst = ((ClassScope)Scopes[i]).Class.Instance;
  334. break;
  335. }
  336. }
  337. if (selfInst != null && newScope.ParameterTypes.Length > 0) {
  338. newScope.ParameterTypes[0].AddTypes(funcdef.Parameters[0], _unit, selfInst.SelfSet);
  339. }
  340. }
  341. }
  342. public override bool Walk(FunctionDefinition node) {
  343. if (node.Body == null) {
  344. // invalid function body
  345. return false;
  346. }
  347. var newScope = this._unit.DeclaringModule.NodeVariables[node].First() as FunctionInfo;
  348. Debug.Assert(newScope != null);
  349. // TODO: __new__ in class should assign returnValue
  350. var curClass = CurrentClass;
  351. if (curClass != null) {
  352. // wire up information about the class
  353. // TODO: Should follow MRO
  354. var bases = LookupBaseMethods(node.Name, curClass.Class.Bases, node, _unit);
  355. foreach (var ns in bases) {
  356. if (ns is BuiltinMethodInfo) {
  357. PropagateBaseParams(newScope, ns);
  358. }
  359. }
  360. }
  361. ProcessFunctionDecorators(node, newScope);
  362. // process parameters
  363. int len = Math.Min(node.Parameters.Count, newScope.ParameterTypes.Length);
  364. for (int i = 0; i < len; i++) {
  365. var p = node.Parameters[i];
  366. var v = newScope.ParameterTypes[i];
  367. if (p.DefaultValue != null) {
  368. var val = _eval.Evaluate(p.DefaultValue);
  369. if (val != null) {
  370. v.AddTypes(p, _unit, val);
  371. }
  372. }
  373. }
  374. // process body
  375. WalkBody(node.Body, newScope._analysisUnit);
  376. return false;
  377. }
  378. private void WalkBody(Node node, AnalysisUnit unit) {
  379. var oldUnit = _unit;
  380. var eval = _eval;
  381. _unit = unit;
  382. _eval = new ExpressionEvaluator(unit);
  383. try {
  384. node.Walk(this);
  385. } finally {
  386. _unit = oldUnit;
  387. _eval = eval;
  388. }
  389. }
  390. public override bool Walk(IfStatement node) {
  391. foreach (var test in node.Tests) {
  392. _eval.Evaluate(test.Test);
  393. test.Body.Walk(this);
  394. }
  395. if (node.ElseStatement != null) {
  396. node.ElseStatement.Walk(this);
  397. }
  398. return true;
  399. }
  400. public override bool Walk(ImportStatement node) {
  401. var iinfo = new ImportInfo("", node.Span);
  402. GlobalScope.Imports[node] = iinfo;
  403. int len = Math.Min(node.Names.Count, node.AsNames.Count);
  404. for (int i = 0; i < len; i++) {
  405. var impNode = node.Names[i];
  406. var newName = node.AsNames[i];
  407. var strImpName = impNode.MakeString();
  408. iinfo.Types.Add(new[] { strImpName, newName });
  409. if (strImpName == "clr") {
  410. GlobalScope.ShowClr = true;
  411. } else if (strImpName == "wpf") {
  412. AddWpfReferences();
  413. }
  414. var saveName = (String.IsNullOrEmpty(newName)) ? strImpName : newName;
  415. ModuleReference modRef;
  416. var def = Scopes[Scopes.Length - 1].CreateVariable(impNode, _unit, saveName);
  417. if (ProjectState.Modules.TryGetValue(strImpName, out modRef)) {
  418. if (modRef.Module != null) {
  419. ModuleInfo mi = modRef.Module as ModuleInfo;
  420. if (mi != null) {
  421. mi.ModuleDefinition.AddDependency(_unit);
  422. }
  423. def.AddTypes(impNode, _unit, modRef.Module.SelfSet);
  424. continue;
  425. } else {
  426. modRef.References.Add(_unit);
  427. }
  428. } else {
  429. ProjectState.Modules[strImpName] = modRef = new ModuleReference();
  430. if (modRef.References == null) {
  431. modRef.References = new HashSet<AnalysisUnit>();
  432. }
  433. modRef.References.Add(_unit);
  434. }
  435. var builtinRefs = ProjectState.GetReflectedNamespaces(impNode.Names, impNode.Names.Count > 1 && !String.IsNullOrEmpty(newName));
  436. if (builtinRefs != null && builtinRefs.Length > 0) {
  437. GlobalScope.ShowClr = true;
  438. var ns = ProjectState.GetNamespaceFromObjects(builtinRefs);
  439. // TODO: Should we pony up a fake module for the module we failed to resolve?
  440. if (ns != null) {
  441. def.AddTypes(impNode, _unit, ns.SelfSet);
  442. }
  443. } else {
  444. }
  445. }
  446. return true;
  447. }
  448. private void AddWpfReferences() {
  449. ProjectState.AddAssembly(typeof(System.Windows.Markup.XamlReader).Assembly); // PresentationFramework
  450. ProjectState.AddAssembly(typeof(System.Windows.Clipboard).Assembly); // PresentationCore
  451. ProjectState.AddAssembly(typeof(System.Windows.DependencyProperty).Assembly); // WindowsBase
  452. ProjectState.AddAssembly(typeof(System.Xaml.XamlReader).Assembly); // System.Xaml
  453. }
  454. public override bool Walk(ReturnStatement node) {
  455. var curFunc = CurrentFunction;
  456. if (node.Expression != null && curFunc != null) {
  457. var lookupRes = _eval.Evaluate(node.Expression);
  458. var retVal = curFunc.Function.ReturnValue;
  459. int typeCount = retVal.Types.Count;
  460. foreach (var type in lookupRes) {
  461. retVal.AddTypes(node, _unit, type);
  462. }
  463. if (typeCount != retVal.Types.Count) {
  464. retVal.EnqueueDependents();
  465. }
  466. }
  467. return true;
  468. }
  469. public override bool Walk(WithStatement node) {
  470. var ctxMgr = _eval.Evaluate(node.ContextManager);
  471. if (node.Variable != null) {
  472. AssignTo(node, node.Variable, ctxMgr);
  473. }
  474. return true;
  475. }
  476. public override bool Walk(PrintStatement node) {
  477. foreach (var expr in node.Expressions) {
  478. _eval.Evaluate(expr);
  479. }
  480. return false;
  481. }
  482. public override bool Walk(AssertStatement node) {
  483. _eval.EvaluateMaybeNull(node.Test);
  484. _eval.EvaluateMaybeNull(node.Message);
  485. return false;
  486. }
  487. public override bool Walk(DelStatement node) {
  488. foreach (var expr in node.Expressions) {
  489. DeleteExpression(expr);
  490. }
  491. return false;
  492. }
  493. private void DeleteExpression(Expression expr) {
  494. NameExpression name = expr as NameExpression;
  495. if (name != null) {
  496. var variable = _eval.LookupVariableByName(name.Name, expr);
  497. if (variable != null) {
  498. variable.AddReference(name, _unit);
  499. }
  500. }
  501. IndexExpression index = expr as IndexExpression;
  502. if (index != null) {
  503. var values = _eval.Evaluate(index.Target);
  504. var indexValues = _eval.Evaluate(index.Index);
  505. foreach (var value in values) {
  506. value.DeleteIndex(index, _unit, indexValues);
  507. }
  508. }
  509. MemberExpression member = expr as MemberExpression;
  510. if (member != null) {
  511. var values = _eval.Evaluate(member.Target);
  512. foreach (var value in values) {
  513. value.DeleteMember(member, _unit, member.Name);
  514. }
  515. }
  516. ParenthesisExpression paren = expr as ParenthesisExpression;
  517. if (paren != null) {
  518. DeleteExpression(paren.Expression);
  519. }
  520. SequenceExpression seq = expr as SequenceExpression;
  521. if (seq != null) {
  522. foreach (var item in seq.Items) {
  523. DeleteExpression(item);
  524. }
  525. }
  526. }
  527. public override bool Walk(RaiseStatement node) {
  528. _eval.EvaluateMaybeNull(node.Value);
  529. _eval.EvaluateMaybeNull(node.Traceback);
  530. _eval.EvaluateMaybeNull(node.ExceptType);
  531. return false;
  532. }
  533. public override bool Walk(WhileStatement node) {
  534. _eval.Evaluate(node.Test);
  535. node.Body.Walk(this);
  536. if (node.ElseStatement != null) {
  537. node.ElseStatement.Walk(this);
  538. }
  539. return false;
  540. }
  541. public override bool Walk(TryStatement node) {
  542. node.Body.Walk(this);
  543. if (node.Handlers != null) {
  544. foreach (var handler in node.Handlers) {
  545. ISet<Namespace> test = EmptySet<Namespace>.Instance;
  546. bool madeSet = false;
  547. if (handler.Test != null) {
  548. var testTypes = _eval.Evaluate(handler.Test);
  549. if (handler.Target != null) {
  550. foreach (var type in testTypes) {
  551. ClassInfo klass = type as ClassInfo;
  552. if (klass != null) {
  553. test = test.Union(klass.Instance.SelfSet, ref madeSet);
  554. }
  555. BuiltinClassInfo builtinClass = type as BuiltinClassInfo;
  556. if (builtinClass != null) {
  557. test = test.Union(builtinClass.Instance.SelfSet, ref madeSet);
  558. }
  559. }
  560. AssignTo(handler, handler.Target, test);
  561. }
  562. }
  563. handler.Body.Walk(this);
  564. }
  565. }
  566. if (node.Finally != null) {
  567. node.Finally.Walk(this);
  568. }
  569. if (node.Else != null) {
  570. node.Else.Walk(this);
  571. }
  572. return false;
  573. }
  574. }
  575. }