blob: 35b68b1fa0aa07aa0f1b61ff4847dd2f0c488353 [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2005, 2016 IBM Corporation and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
*******************************************************************************/
package org.eclipse.dltk.python.internal.core.evaluation;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import org.eclipse.dltk.ast.ASTNode;
import org.eclipse.dltk.ast.ASTVisitor;
import org.eclipse.dltk.ast.declarations.Argument;
import org.eclipse.dltk.ast.declarations.MethodDeclaration;
import org.eclipse.dltk.ast.declarations.ModuleDeclaration;
import org.eclipse.dltk.ast.declarations.TypeDeclaration;
import org.eclipse.dltk.ast.expressions.Expression;
import org.eclipse.dltk.ast.references.SimpleReference;
import org.eclipse.dltk.ast.references.VariableReference;
import org.eclipse.dltk.ast.statements.Statement;
import org.eclipse.dltk.python.parser.ast.PythonImportFromStatement;
import org.eclipse.dltk.python.parser.ast.PythonImportStatement;
import org.eclipse.dltk.python.parser.ast.expressions.Assignment;
import org.eclipse.dltk.python.parser.ast.expressions.ExtendedVariableReference;
import org.eclipse.dltk.python.parser.ast.expressions.PythonImportAsExpression;
import org.eclipse.dltk.python.parser.ast.expressions.PythonImportExpression;
public class PythonASTFindVisitor extends ASTVisitor {
private String fName = null;
private List/* < ASTNode > */fAppropriateNodes = new ArrayList/* < ASTNode > */();
private Map/* < ASTNode, ASTNode> */fParentsMap = new HashMap/*
* < ASTNode,
* ASTNode>
*/();
private boolean fDontVisitMethods = false;
private int innerCount = 0;
List/* < ASTNode > */fParents = new ArrayList/* < ASTNode > */();
public PythonASTFindVisitor(String name) {
fName = name;
}
public PythonASTFindVisitor(String name, boolean dontVisitClassOrMethod) {
fName = name;
fDontVisitMethods = dontVisitClassOrMethod;
}
void putChild(ASTNode node) {
ASTNode parent = null;
if (this.fParents.size() > 0) {
parent = (ASTNode)this.fParents.get(this.fParents.size() - 1);
}
this.fParentsMap.put(node, parent);
}
void putPrevChild(ASTNode node) {
ASTNode parent = null;
if (this.fParents.size() > 1) {
parent = (ASTNode)this.fParents.get(this.fParents.size() - 2);
}
this.fParentsMap.put(node, parent);
}
public List/* < ASTNode > */getNodes() {
return this.fAppropriateNodes;
}
public Map/* < ASTNode, ASTNode > */getParents() {
return this.fParentsMap;
}
@Override
public boolean visit(Expression expression) throws Exception {
this.putChild(expression);
if (expression instanceof Assignment) {
this.fParents.add(expression);
Assignment assignment = (Assignment) expression;
Statement left = assignment.getLeft();
if (left instanceof SimpleReference) {
if (((SimpleReference) left).getName().equals(this.fName)) {
this.fAppropriateNodes.add(expression);
}
}
// FIXME: Add correct handling of this here.
if (left instanceof ExtendedVariableReference) {
ExtendedVariableReference ref = (ExtendedVariableReference) left;
if (ref.isDot(0)) {
Expression first = ref.getExpression(0);
Expression second = ref.getExpression(1);
if (first instanceof VariableReference
&& ((VariableReference) first).getName().equals(
"self")) {
if (second instanceof VariableReference
&& ((VariableReference) second).getName()
.equals(this.fName)) {
this.fAppropriateNodes.add(expression);
List/*<Expression>*/ expressions = ref.getExpressions();
Iterator i = expressions.iterator();
while( i.hasNext() ) {
Expression exp = (Expression)i.next();
this.fParentsMap.put(exp, ref);
}
}
}
}
}
} else if (expression instanceof ExtendedVariableReference) {
// add child parents to map.
ExtendedVariableReference ref = (ExtendedVariableReference) expression;
List/*<Expression>*/ expressions = ref.getExpressions();
Iterator i = expressions.iterator();
while( i.hasNext() ) {
Expression exp = (Expression)i.next();
this.fParentsMap.put(exp, ref);
}
return false;
} else {
this.fParents.add(expression);
}
// TODO: Add lambda handling here.
return true;
}
@Override
public boolean visit(MethodDeclaration method) throws Exception {
this.innerCount++;
if (this.innerCount > 1) {
if (fDontVisitMethods) {
this.innerCount--;
return false;
}
}
this.putChild(method);
this.fParents.add(method);
if (method.getName().equals(this.fName)) {
this.fAppropriateNodes.add(method);
}
return true;
}
@Override
public boolean visit(Statement statement) throws Exception {
if (statement instanceof Argument) {
this.putPrevChild(statement);
} else {
this.putChild(statement);
}
if (statement instanceof PythonImportFromStatement) {
PythonImportFromStatement importStatement = (PythonImportFromStatement) statement;
Map/*<String, String>*/ importedAsNames = importStatement
.getImportedAsNames();
if (importedAsNames.containsValue(this.fName)) {
this.fAppropriateNodes.add(statement);
return false;
}
}
if (statement instanceof PythonImportStatement) {
PythonImportStatement importStatement = (PythonImportStatement) statement;
List/*<Expression>*/ imports = importStatement.getImports();
Iterator i = imports.iterator();
while( i.hasNext() ) {
Expression imp = (Expression)i.next();
String name = "";
if (imp instanceof PythonImportExpression) {
name = ((PythonImportExpression) imp).getName();
} else if (imp instanceof PythonImportAsExpression) {
name = ((PythonImportAsExpression) imp).getAsName();
}
if (name.equals(this.fName)) {
this.fAppropriateNodes.add(statement);
break;
}
}
return false;
}
// if( !(statement instanceof Block ) ) {
this.fParents.add(statement);
// }
return true;
}
@Override
public boolean visit(ModuleDeclaration declaration) throws Exception {
this.innerCount++;
if (this.innerCount > 1) {
if (fDontVisitMethods) {
this.innerCount--;
return false;
}
}
this.fParents.add(declaration);
return true;
}
@Override
public boolean visit(TypeDeclaration typeDeclaration) throws Exception {
this.innerCount++;
if (this.innerCount > 1) {
if (fDontVisitMethods) {
this.innerCount--;
return false;
}
}
this.putChild(typeDeclaration);
this.fParents.add(typeDeclaration);
if (typeDeclaration.getName().equals(this.fName)) {
this.fAppropriateNodes.add(typeDeclaration);
}
return true;
}
@Override
public boolean endvisit(Expression s) throws Exception {
// if( s instanceof Assignment ) {
this.fParents.remove(s);
// }
return true;
}
@Override
public boolean endvisit(MethodDeclaration method) throws Exception {
this.innerCount--;
this.fParents.remove(method);
return true;
}
@Override
public boolean endvisit(ModuleDeclaration declaration) throws Exception {
this.innerCount--;
this.fParents.remove(declaration);
return true;
}
@Override
public boolean endvisit(Statement statement) throws Exception {
// if( !( statement instanceof Block ) ) {
this.fParents.remove(statement);
// }
return true;
}
@Override
public boolean endvisit(TypeDeclaration typeDeclaration) throws Exception {
this.innerCount--;
this.fParents.remove(typeDeclaration);
return true;
}
}