blob: d6eac75072f2745f2788cf8967382a9adcd201bf [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2005, 2007 IBM Corporation and others.
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License v. 2.0 which is available at
* http://www.eclipse.org/legal/epl-2.0.
*
* SPDX-License-Identifier: EPL-2.0
*
*******************************************************************************/
package org.eclipse.dltk.python.internal.core.evaluation;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import org.eclipse.dltk.ast.ASTNode;
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.core.IMethod;
import org.eclipse.dltk.core.IModelElement;
import org.eclipse.dltk.core.IModule;
import org.eclipse.dltk.core.IType;
import org.eclipse.dltk.evaluation.types.ModelModuleType;
import org.eclipse.dltk.evaluation.types.UnknownType;
import org.eclipse.dltk.python.parser.ast.expressions.Assignment;
import org.eclipse.dltk.ti.types.IEvaluatedType;
public class PythonTypeEvaluator {
/**
* Evaluate last from module import. Evaluate last declaration of element
* for correct type detection. Because of that model holds only declaration
* of element.
*
* @param modelElement
* @return
*/
public static IEvaluatedType evaluateLast(IModelElement modelElement) {
return evaluate(modelElement);
}
/**
* Evaluate type from model.
*
* @param modelElement
* @return
*/
public static IEvaluatedType evaluate(IModelElement modelElement) {
if (isAppropriateElement(modelElement)) {
try {
IModule module = PythonTypeEvaluatorUtils
.getElementModule(modelElement);
ModuleDeclaration moduleForElement = PythonTypeEvaluatorUtils
.parseModuleForElement(modelElement);
PythonASTFindVisitor findVisitor = PythonTypeEvaluatorUtils
.findElementsByModelElement(moduleForElement,
modelElement);
Map/* < ASTNode, ASTNode > */parents = findVisitor
.getParents();
// List< ASTNode > allNodes = findVisitor.getNodes( );
List/* < ASTNode > */neededDeclarations = filterASTNodes(
parents, modelElement, findVisitor);
int elementKind = modelElement.getElementType();
// IScriptProject project = modelElement.getScriptProject();
PythonASTTypeEvaluator astEvaluator = new PythonASTTypeEvaluator(
module, moduleForElement, parents);
// Only list of possible needed elements.
if (elementKind == IModelElement.METHOD) {
// Method should be one. If correct source code.
int count = 0;
IEvaluatedType type = null;
Iterator i = neededDeclarations.iterator();
while (i.hasNext()) {
ASTNode node = (ASTNode) i.next();
if (count > 0) {
break;
}
type = astEvaluator.evaluateASTNode(node, null);
count++;
}
if (count > 1) {
// TODO: Add error handling here.
}
if (type != null) {
return type;
}
return UnknownType.INSTANCE;
} else if (elementKind == IModelElement.FIELD) {
// TODO: Add multiple values handling here.
Iterator i = neededDeclarations.iterator();
while (i.hasNext()) {
ASTNode node = (ASTNode) i.next();
return astEvaluator.evaluateASTNode(node, null);
}
}
} catch (Exception exception) {
exception.printStackTrace();
return UnknownType.INSTANCE;
}
} else if (modelElement.getElementType() == IModelElement.SOURCE_MODULE) {
return new ModelModuleType((IModule) modelElement);
}
return UnknownType.INSTANCE;
}
public static boolean isAppropriateElement(IModelElement modelElement) {
if (modelElement.getElementType() == IModelElement.FIELD
|| modelElement.getElementType() == IModelElement.METHOD) {
return true;
}
return false;
}
/**
* Clear statistics.
*
*/
public static void clearStats() {
}
private static List/* <ASTNode> */filterASTNodes(
Map/* <ASTNode, ASTNode> */parents, IModelElement modelElement,
PythonASTFindVisitor visitor) throws Exception {
List/* <ASTNode> */elementDeclarations = visitor.getNodes();
// Needed for this node declarations.
List/* <ASTNode> */neededDeclarations = new ArrayList/* <ASTNode> */();
int elementKind = modelElement.getElementType();
// If this is field then gets parent.
IModelElement parentElement = modelElement;
if (elementKind == IModelElement.FIELD) {
parentElement = modelElement.getParent();
}
Iterator i = elementDeclarations.iterator();
while (i.hasNext()) {
ASTNode node = (ASTNode) i.next();
try {
if (elementKind == IModelElement.METHOD) {
if (node instanceof MethodDeclaration) {
if (filterByModel(parents, parentElement,
PythonTypeEvaluatorUtils.getModelLikeNode(
parents, node))) {
neededDeclarations.add(node);
}
}
} else if (elementKind == IModelElement.FIELD) {
if (node instanceof Assignment) {
if (filterByModel(parents, parentElement,
PythonTypeEvaluatorUtils.getModelLikeNode(
parents, node))) {
neededDeclarations.add(node);
}
}
}
} catch (Exception e) {
e.printStackTrace();
}
}
return neededDeclarations;
}
/**
* Filters ast element by Model.
*
* @param modelElement
* @param node
* @return
*/
public static boolean filterByModel(Map/* <ASTNode, ASTNode> */parents,
IModelElement modelElement, ASTNode node) throws Exception {
if (node == null || modelElement == null) {
return false;
}
// Go to parents until module.
if (modelElement.getElementType() == IModelElement.METHOD) {
IMethod iMethod = (IMethod) modelElement;
// Find needed ast method declaration and check to top for equal
// name and
// types.
if (node instanceof MethodDeclaration) {
MethodDeclaration method = (MethodDeclaration) node;
if (!method.getName().equals(iMethod.getElementName())) {
return false;
}
if (method.getArguments().size() != iMethod.getParameters().length) {
return false;
}
if (parents.containsKey(node)) {
return filterByModel(parents, modelElement.getParent(),
PythonTypeEvaluatorUtils.getModelLikeNode(parents,
(ASTNode) parents.get(node)));
}
}
} else if (modelElement.getElementType() == IModelElement.TYPE) {
IType iClass = (IType) modelElement;
// Find needed ast method declaration and check to top for equal
// name and
// types.
if (node instanceof TypeDeclaration) {
TypeDeclaration method = (TypeDeclaration) node;
if (!method.getName().equals(iClass.getElementName())) {
return false;
}
if (parents.containsKey(node)) {
return filterByModel(parents, modelElement.getParent(),
PythonTypeEvaluatorUtils.getModelLikeNode(parents,
(ASTNode) parents.get(node)));
}
}
} else if (modelElement.getElementType() == IModelElement.SOURCE_MODULE) {
IModule iModule = (IModule) modelElement;
if (node instanceof ModuleDeclaration) {
return true;
}
}
return false;
}
/**
* Evaluate call using argument types. globals must be last from selected
* module.
*
* @param modelElement
* @param callHolder
* @return TODO: Add correct implementation here
*/
public static IEvaluatedType evaluateCall(IModelElement modelElement,
List/* <IEvaluatedType> */callHolder) {
return evaluate(modelElement);
}
}