PageRenderTime 46ms CodeModel.GetById 16ms RepoModel.GetById 1ms app.codeStats 0ms

/plugins/com.python.pydev.analysis/src/com/python/pydev/analysis/scopeanalysis/ScopeAnalysis.java

https://github.com/MrGreen123/Pydev
Java | 363 lines | 243 code | 50 blank | 70 comment | 45 complexity | 87c625bd720dd1b364100839fb6a8fd7 MD5 | raw file
  1. /**
  2. * Copyright (c) 2005-2011 by Appcelerator, Inc. All Rights Reserved.
  3. * Licensed under the terms of the Eclipse Public License (EPL).
  4. * Please see the license.txt included with this distribution for details.
  5. * Any modifications to this file must keep this entire header intact.
  6. */
  7. package com.python.pydev.analysis.scopeanalysis;
  8. import java.util.ArrayList;
  9. import java.util.Iterator;
  10. import java.util.List;
  11. import org.eclipse.core.runtime.CoreException;
  12. import org.python.pydev.core.ILocalScope;
  13. import org.python.pydev.core.IModule;
  14. import org.python.pydev.core.Tuple;
  15. import org.python.pydev.core.docutils.PySelection;
  16. import org.python.pydev.core.log.Log;
  17. import org.python.pydev.editor.codecompletion.revisited.modules.SourceModule;
  18. import org.python.pydev.parser.jython.SimpleNode;
  19. import org.python.pydev.parser.jython.ast.Attribute;
  20. import org.python.pydev.parser.jython.ast.ClassDef;
  21. import org.python.pydev.parser.jython.ast.FunctionDef;
  22. import org.python.pydev.parser.jython.ast.Name;
  23. import org.python.pydev.parser.jython.ast.Str;
  24. import org.python.pydev.parser.jython.ast.commentType;
  25. import org.python.pydev.parser.jython.ast.decoratorsType;
  26. import org.python.pydev.parser.jython.ast.exprType;
  27. import org.python.pydev.parser.jython.ast.stmtType;
  28. import org.python.pydev.parser.visitors.NodeUtils;
  29. import org.python.pydev.parser.visitors.scope.ASTEntry;
  30. import org.python.pydev.parser.visitors.scope.SequencialASTIteratorVisitor;
  31. public class ScopeAnalysis {
  32. public static List<ASTEntry> getAttributeReferences(String occurencesFor, SimpleNode simpleNode) {
  33. //default is accepting all
  34. return getAttributeReferences(occurencesFor, simpleNode, AttributeReferencesVisitor.ACCEPT_ALL);
  35. }
  36. /**
  37. * @return the list of entries with the name parts of attributes (not taking into account its first
  38. * part) that are equal to the occurencesFor string.
  39. */
  40. public static List<ASTEntry> getAttributeReferences(String occurencesFor, SimpleNode simpleNode, int accept) {
  41. List<ASTEntry> ret = new ArrayList<ASTEntry>();
  42. AttributeReferencesVisitor visitor = AttributeReferencesVisitor.create(simpleNode, accept);
  43. Iterator<ASTEntry> iterator = visitor.getNamesIterator();
  44. while(iterator.hasNext()){
  45. ASTEntry entry = iterator.next();
  46. String rep = NodeUtils.getFullRepresentationString(entry.node);
  47. if (rep.equals(occurencesFor)){
  48. ret.add(entry);
  49. }
  50. }
  51. return ret;
  52. }
  53. /**
  54. * @param occurencesFor the string we're looking for
  55. * @param module the module where we want to find the occurrences
  56. * @param scope the scope we're in
  57. * @return tuple with:
  58. * 1st element: the node where the local was found (may be null)
  59. * 2nd element: a list of entries with the occurrences
  60. */
  61. public static Tuple<SimpleNode, List<ASTEntry>> getLocalOccurrences(String occurencesFor, IModule module, ILocalScope scope) {
  62. SimpleNode simpleNode=null;
  63. if(scope.getScopeStack().size() > 0){
  64. simpleNode = (SimpleNode) scope.getScopeStack().peek();
  65. }else if (module instanceof SourceModule){
  66. SourceModule m = (SourceModule) module;
  67. simpleNode = m.getAst();
  68. }
  69. if (simpleNode == null){
  70. return new Tuple<SimpleNode, List<ASTEntry>>(null, new ArrayList<ASTEntry>());
  71. }
  72. return new Tuple<SimpleNode, List<ASTEntry>>(simpleNode, ScopeAnalysis.getLocalOccurrences(occurencesFor, simpleNode));
  73. }
  74. /**
  75. * @param occurencesFor the string we're looking for
  76. * @param simpleNode we will want the occurences below this node
  77. * @return a list of entries with the occurrences
  78. */
  79. public static List<ASTEntry> getLocalOccurrences(String occurencesFor, SimpleNode simpleNode) {
  80. return ScopeAnalysis.getLocalOccurrences(occurencesFor, simpleNode, true);
  81. }
  82. /**
  83. * @return a list of ast entries that are found inside strings.
  84. */
  85. public static List<ASTEntry> getStringOccurrences(final String occurencesFor, SimpleNode simpleNode) {
  86. final List<ASTEntry> ret = new ArrayList<ASTEntry>();
  87. SequencialASTIteratorVisitor visitor = new SequencialASTIteratorVisitor(){
  88. @Override
  89. public Object visitStr(Str node) throws Exception {
  90. String str = NodeUtils.getStringToPrint(node);
  91. List<Name> names = checkSimpleNodeForTokenMatch(occurencesFor, new ArrayList<Name>(), node, str);
  92. for (Name name : names){
  93. ASTEntry astEntryToAdd = atomic(name);
  94. astEntryToAdd.setAdditionalInfo(AstEntryScopeAnalysisConstants.AST_ENTRY_FOUND_LOCATION, AstEntryScopeAnalysisConstants.AST_ENTRY_FOUND_IN_STRING);
  95. ret.add(astEntryToAdd);
  96. }
  97. return super.visitStr(node);
  98. }
  99. };
  100. try {
  101. simpleNode.accept(visitor);
  102. } catch (Exception e) {
  103. throw new RuntimeException(e);
  104. }
  105. return ret;
  106. }
  107. /**
  108. * @return a list of ast entries that are found inside comments.
  109. */
  110. public static List<ASTEntry> getCommentOccurrences(final String occurencesFor, SimpleNode simpleNode) {
  111. final List<ASTEntry> ret = new ArrayList<ASTEntry>();
  112. SequencialASTIteratorVisitor visitor = new SequencialASTIteratorVisitor(){
  113. @Override
  114. protected Object unhandled_node(SimpleNode node) throws Exception {
  115. Object r = super.unhandled_node(node);
  116. //now, we have to check it for occurrences in comments and strings too... (and create
  117. //names for those)
  118. checkNode(occurencesFor, ret, node);
  119. return r;
  120. }
  121. @Override
  122. public Object visitClassDef(ClassDef node) throws Exception {
  123. Object r = super.visitClassDef(node);
  124. checkNode(occurencesFor, ret, node);
  125. return r;
  126. }
  127. @Override
  128. public Object visitFunctionDef(FunctionDef node) throws Exception {
  129. Object r = super.visitFunctionDef(node);
  130. checkNode(occurencesFor, ret, node);
  131. return r;
  132. }
  133. private void checkNode(final String occurencesFor, final List<ASTEntry> ret, SimpleNode node) {
  134. List<Name> names = checkComments(node.specialsBefore, occurencesFor);
  135. names.addAll(checkComments(node.specialsAfter, occurencesFor));
  136. for (Name name : names){
  137. ASTEntry astEntryToAdd = atomic(name);
  138. astEntryToAdd.setAdditionalInfo(AstEntryScopeAnalysisConstants.AST_ENTRY_FOUND_LOCATION, AstEntryScopeAnalysisConstants.AST_ENTRY_FOUND_IN_COMMENT);
  139. ret.add(astEntryToAdd);
  140. }
  141. }
  142. };
  143. try {
  144. simpleNode.accept(visitor);
  145. } catch (Exception e) {
  146. throw new RuntimeException(e);
  147. }
  148. return ret;
  149. }
  150. /**
  151. * @return a list of occurrences with the matches we're looking for.
  152. * Does only return the first name in attributes if onlyFirstAttribPart is true (otherwise will check all attribute parts)
  153. */
  154. public static List<ASTEntry> getLocalOccurrences(final String occurencesFor, SimpleNode simpleNode, final boolean onlyFirstAttribPart) {
  155. List<ASTEntry> ret = new ArrayList<ASTEntry>();
  156. SequencialASTIteratorVisitor visitor = new SequencialASTIteratorVisitor(){
  157. @Override
  158. public Object visitAttribute(Attribute node) throws Exception {
  159. if(onlyFirstAttribPart){
  160. //this will visit the attribute parts if call, subscript, etc.
  161. AbstractScopeAnalyzerVisitor.visitNeededAttributeParts(node, this);
  162. List<SimpleNode> attributeParts = NodeUtils.getAttributeParts(node);
  163. atomic(attributeParts.get(0)); //an attribute should always have many parts
  164. traverse(attributeParts.get(0));
  165. return null;
  166. }else{
  167. return super.visitAttribute(node);
  168. }
  169. }
  170. };
  171. if(simpleNode instanceof FunctionDef){
  172. //all that because we don't want to visit the name of the function if we've started in a function scope
  173. FunctionDef d = (FunctionDef) simpleNode;
  174. try {
  175. //decorators
  176. if(d.decs != null){
  177. for(decoratorsType dec : d.decs){
  178. if(dec != null){
  179. dec.accept(visitor);
  180. }
  181. }
  182. }
  183. //don't do d.args directly because we don't want to check the 'defaults'
  184. if(d.args != null){
  185. if(d.args.args != null){
  186. for(exprType arg:d.args.args){
  187. arg.accept(visitor);
  188. }
  189. }
  190. if(d.args.vararg != null){
  191. d.args.vararg.accept(visitor);
  192. }
  193. if(d.args.kwarg != null){
  194. d.args.kwarg.accept(visitor);
  195. }
  196. //visit keyword only args
  197. if(d.args.kwonlyargs != null){
  198. for(exprType expr : d.args.kwonlyargs){
  199. expr.accept(visitor);
  200. }
  201. }
  202. }
  203. //and at last... the body
  204. if(d.body != null){
  205. for(stmtType exp: d.body){
  206. if(exp != null){
  207. exp.accept(visitor);
  208. }
  209. }
  210. }
  211. } catch (Exception e) {
  212. throw new RuntimeException(e);
  213. }
  214. }else{
  215. try {
  216. simpleNode.accept(visitor);
  217. } catch (Exception e) {
  218. throw new RuntimeException(e);
  219. }
  220. }
  221. Iterator<ASTEntry> iterator = visitor.getNamesIterator();
  222. while(iterator.hasNext()){
  223. ASTEntry entry = iterator.next();
  224. //SimpleNode nameNode = entry.getNameNode();
  225. //if(!occurencesFor.isParamRename){
  226. // if(nameNode instanceof NameTok){
  227. // NameTok name = (NameTok) nameNode;
  228. // if(name.ctx == NameTok.KeywordName){
  229. // continue;
  230. // }
  231. // }
  232. //}
  233. if (occurencesFor.equals(entry.getName())){
  234. ret.add(entry);
  235. }
  236. }
  237. return ret;
  238. }
  239. /**
  240. * Search for the attributes that start with the passed parameter.
  241. *
  242. * @param occurencesFor has to be the full name of the attribute we're looking for in this case.
  243. *
  244. * So, if you want something as self.aa, the occurencesFor must be 'self.aa'. If the attribute
  245. * is longer, it will still be returned (because when looking for self.aa.m1, we will
  246. * actually have 2 attributes returned, one for self.aa and another for aa.m1, in which case
  247. * we will return the one correspondent to self.aa)
  248. */
  249. public static List<ASTEntry> getAttributeOccurrences(String occurencesFor, SimpleNode simpleNode){
  250. List<ASTEntry> ret = new ArrayList<ASTEntry>();
  251. SequencialASTIteratorVisitor visitor = SequencialASTIteratorVisitor.create(simpleNode);
  252. Iterator<ASTEntry> iterator = visitor.getIterator(Attribute.class);
  253. while(iterator.hasNext()){
  254. ASTEntry entry = iterator.next();
  255. String rep = NodeUtils.getFullRepresentationString(entry.node, true);
  256. if (rep.equals(occurencesFor)){
  257. ret.add(entry);
  258. }
  259. }
  260. return ret;
  261. }
  262. /**
  263. * @param specials a list that may contain comments
  264. * @param match a string to match in the comments
  265. * @return a list with names matching the gives token
  266. */
  267. public static List<Name> checkComments(List<Object> specials, String match) {
  268. List<Name> r = new ArrayList<Name>();
  269. if(specials != null){
  270. for(Object s:specials){
  271. if(s instanceof commentType){
  272. commentType comment = (commentType) s;
  273. checkSimpleNodeForTokenMatch(match, r, comment, comment.id);
  274. }
  275. }
  276. }
  277. return r;
  278. }
  279. /**
  280. * Looks for a match in the given string and fills the List<Name> with Names according to those positions.
  281. * @return the list of names (same as ret)
  282. */
  283. public static List<Name> checkSimpleNodeForTokenMatch(String match, List<Name> ret, SimpleNode node, String fullString) {
  284. try {
  285. ArrayList<Integer> offsets = TokenMatching.getMatchOffsets(match, fullString);
  286. List<Integer> lineStartOffsets = PySelection.getLineStartOffsets(fullString);
  287. for (Integer offset : offsets) {
  288. int line=0;
  289. Name name = new Name(match, Name.Artificial, false);
  290. for(Integer lineStartOffset:lineStartOffsets){
  291. if(line == 0 && lineStartOffset > 0){
  292. line = 1;//because it starts with a new line
  293. }
  294. if(lineStartOffset <= offset){
  295. name.beginLine = node.beginLine+line;
  296. if(line == 0){
  297. name.beginColumn = node.beginColumn+offset-lineStartOffset;
  298. }else{
  299. name.beginColumn = offset-lineStartOffset+1;
  300. }
  301. }else{
  302. break;
  303. }
  304. line++;
  305. }
  306. ret.add(name);
  307. }
  308. } catch (CoreException e) {
  309. Log.log(e);
  310. }
  311. return ret;
  312. }
  313. }