/plugins/com.python.pydev.analysis/src/com/python/pydev/analysis/scopeanalysis/ScopeAnalysis.java
Java | 363 lines | 243 code | 50 blank | 70 comment | 45 complexity | 87c625bd720dd1b364100839fb6a8fd7 MD5 | raw file
- /**
- * Copyright (c) 2005-2011 by Appcelerator, Inc. All Rights Reserved.
- * Licensed under the terms of the Eclipse Public License (EPL).
- * Please see the license.txt included with this distribution for details.
- * Any modifications to this file must keep this entire header intact.
- */
- package com.python.pydev.analysis.scopeanalysis;
- import java.util.ArrayList;
- import java.util.Iterator;
- import java.util.List;
- import org.eclipse.core.runtime.CoreException;
- import org.python.pydev.core.ILocalScope;
- import org.python.pydev.core.IModule;
- import org.python.pydev.core.Tuple;
- import org.python.pydev.core.docutils.PySelection;
- import org.python.pydev.core.log.Log;
- import org.python.pydev.editor.codecompletion.revisited.modules.SourceModule;
- import org.python.pydev.parser.jython.SimpleNode;
- import org.python.pydev.parser.jython.ast.Attribute;
- import org.python.pydev.parser.jython.ast.ClassDef;
- import org.python.pydev.parser.jython.ast.FunctionDef;
- import org.python.pydev.parser.jython.ast.Name;
- import org.python.pydev.parser.jython.ast.Str;
- import org.python.pydev.parser.jython.ast.commentType;
- import org.python.pydev.parser.jython.ast.decoratorsType;
- import org.python.pydev.parser.jython.ast.exprType;
- import org.python.pydev.parser.jython.ast.stmtType;
- import org.python.pydev.parser.visitors.NodeUtils;
- import org.python.pydev.parser.visitors.scope.ASTEntry;
- import org.python.pydev.parser.visitors.scope.SequencialASTIteratorVisitor;
- public class ScopeAnalysis {
- public static List<ASTEntry> getAttributeReferences(String occurencesFor, SimpleNode simpleNode) {
- //default is accepting all
- return getAttributeReferences(occurencesFor, simpleNode, AttributeReferencesVisitor.ACCEPT_ALL);
- }
- /**
- * @return the list of entries with the name parts of attributes (not taking into account its first
- * part) that are equal to the occurencesFor string.
- */
- public static List<ASTEntry> getAttributeReferences(String occurencesFor, SimpleNode simpleNode, int accept) {
- List<ASTEntry> ret = new ArrayList<ASTEntry>();
- AttributeReferencesVisitor visitor = AttributeReferencesVisitor.create(simpleNode, accept);
- Iterator<ASTEntry> iterator = visitor.getNamesIterator();
-
- while(iterator.hasNext()){
- ASTEntry entry = iterator.next();
- String rep = NodeUtils.getFullRepresentationString(entry.node);
- if (rep.equals(occurencesFor)){
- ret.add(entry);
- }
- }
- return ret;
- }
-
- /**
- * @param occurencesFor the string we're looking for
- * @param module the module where we want to find the occurrences
- * @param scope the scope we're in
- * @return tuple with:
- * 1st element: the node where the local was found (may be null)
- * 2nd element: a list of entries with the occurrences
- */
- public static Tuple<SimpleNode, List<ASTEntry>> getLocalOccurrences(String occurencesFor, IModule module, ILocalScope scope) {
- SimpleNode simpleNode=null;
-
- if(scope.getScopeStack().size() > 0){
- simpleNode = (SimpleNode) scope.getScopeStack().peek();
-
- }else if (module instanceof SourceModule){
- SourceModule m = (SourceModule) module;
- simpleNode = m.getAst();
- }
-
- if (simpleNode == null){
- return new Tuple<SimpleNode, List<ASTEntry>>(null, new ArrayList<ASTEntry>());
- }
-
- return new Tuple<SimpleNode, List<ASTEntry>>(simpleNode, ScopeAnalysis.getLocalOccurrences(occurencesFor, simpleNode));
- }
- /**
- * @param occurencesFor the string we're looking for
- * @param simpleNode we will want the occurences below this node
- * @return a list of entries with the occurrences
- */
- public static List<ASTEntry> getLocalOccurrences(String occurencesFor, SimpleNode simpleNode) {
- return ScopeAnalysis.getLocalOccurrences(occurencesFor, simpleNode, true);
- }
-
- /**
- * @return a list of ast entries that are found inside strings.
- */
- public static List<ASTEntry> getStringOccurrences(final String occurencesFor, SimpleNode simpleNode) {
- final List<ASTEntry> ret = new ArrayList<ASTEntry>();
-
- SequencialASTIteratorVisitor visitor = new SequencialASTIteratorVisitor(){
- @Override
- public Object visitStr(Str node) throws Exception {
- String str = NodeUtils.getStringToPrint(node);
- List<Name> names = checkSimpleNodeForTokenMatch(occurencesFor, new ArrayList<Name>(), node, str);
- for (Name name : names){
- ASTEntry astEntryToAdd = atomic(name);
- astEntryToAdd.setAdditionalInfo(AstEntryScopeAnalysisConstants.AST_ENTRY_FOUND_LOCATION, AstEntryScopeAnalysisConstants.AST_ENTRY_FOUND_IN_STRING);
- ret.add(astEntryToAdd);
- }
- return super.visitStr(node);
- }
-
- };
- try {
- simpleNode.accept(visitor);
- } catch (Exception e) {
- throw new RuntimeException(e);
- }
- return ret;
- }
- /**
- * @return a list of ast entries that are found inside comments.
- */
- public static List<ASTEntry> getCommentOccurrences(final String occurencesFor, SimpleNode simpleNode) {
- final List<ASTEntry> ret = new ArrayList<ASTEntry>();
- SequencialASTIteratorVisitor visitor = new SequencialASTIteratorVisitor(){
- @Override
- protected Object unhandled_node(SimpleNode node) throws Exception {
- Object r = super.unhandled_node(node);
- //now, we have to check it for occurrences in comments and strings too... (and create
- //names for those)
- checkNode(occurencesFor, ret, node);
- return r;
- }
- @Override
- public Object visitClassDef(ClassDef node) throws Exception {
- Object r = super.visitClassDef(node);
- checkNode(occurencesFor, ret, node);
- return r;
- }
-
- @Override
- public Object visitFunctionDef(FunctionDef node) throws Exception {
- Object r = super.visitFunctionDef(node);
- checkNode(occurencesFor, ret, node);
- return r;
- }
-
- private void checkNode(final String occurencesFor, final List<ASTEntry> ret, SimpleNode node) {
- List<Name> names = checkComments(node.specialsBefore, occurencesFor);
- names.addAll(checkComments(node.specialsAfter, occurencesFor));
- for (Name name : names){
- ASTEntry astEntryToAdd = atomic(name);
- astEntryToAdd.setAdditionalInfo(AstEntryScopeAnalysisConstants.AST_ENTRY_FOUND_LOCATION, AstEntryScopeAnalysisConstants.AST_ENTRY_FOUND_IN_COMMENT);
- ret.add(astEntryToAdd);
- }
- }
-
- };
- try {
- simpleNode.accept(visitor);
- } catch (Exception e) {
- throw new RuntimeException(e);
- }
- return ret;
- }
-
-
- /**
- * @return a list of occurrences with the matches we're looking for.
- * Does only return the first name in attributes if onlyFirstAttribPart is true (otherwise will check all attribute parts)
- */
- public static List<ASTEntry> getLocalOccurrences(final String occurencesFor, SimpleNode simpleNode, final boolean onlyFirstAttribPart) {
- List<ASTEntry> ret = new ArrayList<ASTEntry>();
-
- SequencialASTIteratorVisitor visitor = new SequencialASTIteratorVisitor(){
-
- @Override
- public Object visitAttribute(Attribute node) throws Exception {
- if(onlyFirstAttribPart){
- //this will visit the attribute parts if call, subscript, etc.
- AbstractScopeAnalyzerVisitor.visitNeededAttributeParts(node, this);
-
- List<SimpleNode> attributeParts = NodeUtils.getAttributeParts(node);
- atomic(attributeParts.get(0)); //an attribute should always have many parts
- traverse(attributeParts.get(0));
- return null;
- }else{
- return super.visitAttribute(node);
- }
- }
- };
- if(simpleNode instanceof FunctionDef){
- //all that because we don't want to visit the name of the function if we've started in a function scope
- FunctionDef d = (FunctionDef) simpleNode;
- try {
- //decorators
- if(d.decs != null){
- for(decoratorsType dec : d.decs){
- if(dec != null){
- dec.accept(visitor);
- }
- }
- }
-
- //don't do d.args directly because we don't want to check the 'defaults'
- if(d.args != null){
- if(d.args.args != null){
- for(exprType arg:d.args.args){
- arg.accept(visitor);
- }
- }
- if(d.args.vararg != null){
- d.args.vararg.accept(visitor);
- }
- if(d.args.kwarg != null){
- d.args.kwarg.accept(visitor);
- }
- //visit keyword only args
- if(d.args.kwonlyargs != null){
- for(exprType expr : d.args.kwonlyargs){
- expr.accept(visitor);
- }
- }
- }
-
- //and at last... the body
- if(d.body != null){
- for(stmtType exp: d.body){
- if(exp != null){
- exp.accept(visitor);
- }
- }
- }
- } catch (Exception e) {
- throw new RuntimeException(e);
- }
- }else{
-
- try {
- simpleNode.accept(visitor);
- } catch (Exception e) {
- throw new RuntimeException(e);
- }
- }
-
- Iterator<ASTEntry> iterator = visitor.getNamesIterator();
- while(iterator.hasNext()){
- ASTEntry entry = iterator.next();
- //SimpleNode nameNode = entry.getNameNode();
- //if(!occurencesFor.isParamRename){
- // if(nameNode instanceof NameTok){
- // NameTok name = (NameTok) nameNode;
- // if(name.ctx == NameTok.KeywordName){
- // continue;
- // }
- // }
- //}
- if (occurencesFor.equals(entry.getName())){
- ret.add(entry);
- }
- }
- return ret;
- }
- /**
- * Search for the attributes that start with the passed parameter.
- *
- * @param occurencesFor has to be the full name of the attribute we're looking for in this case.
- *
- * So, if you want something as self.aa, the occurencesFor must be 'self.aa'. If the attribute
- * is longer, it will still be returned (because when looking for self.aa.m1, we will
- * actually have 2 attributes returned, one for self.aa and another for aa.m1, in which case
- * we will return the one correspondent to self.aa)
- */
- public static List<ASTEntry> getAttributeOccurrences(String occurencesFor, SimpleNode simpleNode){
- List<ASTEntry> ret = new ArrayList<ASTEntry>();
- SequencialASTIteratorVisitor visitor = SequencialASTIteratorVisitor.create(simpleNode);
- Iterator<ASTEntry> iterator = visitor.getIterator(Attribute.class);
-
- while(iterator.hasNext()){
- ASTEntry entry = iterator.next();
- String rep = NodeUtils.getFullRepresentationString(entry.node, true);
- if (rep.equals(occurencesFor)){
- ret.add(entry);
- }
- }
- return ret;
- }
-
-
- /**
- * @param specials a list that may contain comments
- * @param match a string to match in the comments
- * @return a list with names matching the gives token
- */
- public static List<Name> checkComments(List<Object> specials, String match) {
- List<Name> r = new ArrayList<Name>();
-
- if(specials != null){
- for(Object s:specials){
- if(s instanceof commentType){
- commentType comment = (commentType) s;
- checkSimpleNodeForTokenMatch(match, r, comment, comment.id);
- }
- }
- }
- return r;
- }
- /**
- * Looks for a match in the given string and fills the List<Name> with Names according to those positions.
- * @return the list of names (same as ret)
- */
- public static List<Name> checkSimpleNodeForTokenMatch(String match, List<Name> ret, SimpleNode node, String fullString) {
- try {
- ArrayList<Integer> offsets = TokenMatching.getMatchOffsets(match, fullString);
- List<Integer> lineStartOffsets = PySelection.getLineStartOffsets(fullString);
-
- for (Integer offset : offsets) {
- int line=0;
- Name name = new Name(match, Name.Artificial, false);
-
- for(Integer lineStartOffset:lineStartOffsets){
- if(line == 0 && lineStartOffset > 0){
- line = 1;//because it starts with a new line
- }
- if(lineStartOffset <= offset){
- name.beginLine = node.beginLine+line;
- if(line == 0){
- name.beginColumn = node.beginColumn+offset-lineStartOffset;
- }else{
- name.beginColumn = offset-lineStartOffset+1;
- }
- }else{
- break;
- }
- line++;
- }
- ret.add(name);
- }
- } catch (CoreException e) {
- Log.log(e);
- }
- return ret;
- }
- }