<commit_before>/*
 * Copyright (C) 2007-2008  <NAME>, <NAME>
 *
 * IFS Institute for Software, HSR Rapperswil, Switzerland
 *
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
 *
 */

package ch.hsr.ifs.pystructure.typeinference.evaluators.types;

import java.util.ArrayList;
import java.util.List;

import org.python.pydev.parser.jython.ast.Attribute;

import ch.hsr.ifs.pystructure.typeinference.basetype.CombinedType;
import ch.hsr.ifs.pystructure.typeinference.basetype.IType;
import ch.hsr.ifs.pystructure.typeinference.contexts.ModuleContext;
import ch.hsr.ifs.pystructure.typeinference.evaluators.base.AbstractEvaluator;
import ch.hsr.ifs.pystructure.typeinference.goals.base.GoalState;
import ch.hsr.ifs.pystructure.typeinference.goals.base.IGoal;
import ch.hsr.ifs.pystructure.typeinference.goals.types.ClassAttributeTypeGoal;
import ch.hsr.ifs.pystructure.typeinference.goals.types.DefinitionTypeGoal;
import ch.hsr.ifs.pystructure.typeinference.goals.types.ExpressionTypeGoal;
import ch.hsr.ifs.pystructure.typeinference.goals.types.ResolveMethodGoal;
import ch.hsr.ifs.pystructure.typeinference.model.base.NodeUtils;
import ch.hsr.ifs.pystructure.typeinference.model.definitions.Class;
import ch.hsr.ifs.pystructure.typeinference.model.definitions.Definition;
import ch.hsr.ifs.pystructure.typeinference.model.definitions.Module;
import ch.hsr.ifs.pystructure.typeinference.model.definitions.Package;
import ch.hsr.ifs.pystructure.typeinference.model.definitions.PathElement;
import ch.hsr.ifs.pystructure.typeinference.results.types.ClassType;
import ch.hsr.ifs.pystructure.typeinference.results.types.ModuleType;
import ch.hsr.ifs.pystructure.typeinference.results.types.PackageType;

/**
 * Evaluator for the type of an attribute node. For example, the result for
 * <code>instance.method</code> would be the method.
 */
public class AttributeTypeEvaluator extends AbstractEvaluator {

	private final Attribute attribute;

	private CombinedType resultType;

	public AttributeTypeEvaluator(ExpressionTypeGoal goal, Attribute attribute) {
		super(goal);
		this.attribute = attribute;

		this.resultType = goal.resultType;
	}

	@Override
	public List<IGoal> init() {
		return wrap(new ExpressionTypeGoal(getGoal().getContext(), attribute.value));
	}

	@Override
	public List<IGoal> subgoalDone(IGoal subgoal, GoalState state) {
		if (state == GoalState.RECURSIVE) {
			// RECURSIVE could mean something like that:
			//   self.attr = self.attr
			// This doesn't add anything to the result type, so we ignore it.
			return IGoal.NO_GOALS;
		}
		
		List<IGoal> subgoals = new ArrayList<IGoal>();
		
		if (subgoal instanceof ExpressionTypeGoal) {
			ExpressionTypeGoal g = (ExpressionTypeGoal) subgoal;
			
			String attributeName = NodeUtils.getId(attribute.attr);
			for (IType type : g.resultType) {
				if (type instanceof ClassType) {
					// It's either a method or an attribute
					ClassType classType = (ClassType) type;
					Class klass = classType.getKlass();
	
					if (klass != null) {
						ModuleContext context = new ModuleContext(getGoal().getContext(), klass.getModule());
						subgoals.add(new ResolveMethodGoal(context, classType, attributeName));
					} else {
						/* klass is null, this probably means that we are talking about 
						 * an internal or unknown class */
					}
					
				} else if (type instanceof PackageType) {
					PackageType pkgType = (PackageType) type;
	
					Package pkg = pkgType.getPackage();
	
					PathElement child = pkg.getChild(attributeName);
	
					if (child != null) {
	
						if (child instanceof Package) {
							resultType.appendType(new PackageType((Package) child));
						} else if (child instanceof Module) {
							resultType.appendType(new ModuleType((Module) child));
						} else {
							throw new RuntimeException("Got SysPath, evil!");
						}
					} else {
						System.err.println("Unable to find " + attributeName + " in package " + pkg);
//						throw new RuntimeException("Unable to find " + attributeName + " in package " + pkg);
					}
					
				} else if (type instanceof ModuleType) {
					ModuleType moduleType = (ModuleType) type;
					Module module = moduleType.getModule();
	
					List<Definition> definitions = module.getDefinitions(attributeName);
					for (Definition definition : definitions) {
						ModuleContext context = new ModuleContext(getGoal().getContext(), module);
						subgoals.add(new DefinitionTypeGoal(context, definition));
					}
				}
				
				// TODO: PythonMetaclassType
			}
			
		} else if (subgoal instanceof ClassAttributeTypeGoal) {
			ClassAttributeTypeGoal g = (ClassAttributeTypeGoal) subgoal;
			resultType.appendType((CombinedType) g.resultType);
		
		} else if (subgoal instanceof ResolveMethodGoal) {
			ResolveMethodGoal g = (ResolveMethodGoal) subgoal;
			
			if (!g.methodTypes.isEmpty()) {
				resultType.appendType(g.methodTypes);
			} else {
				ClassType classType = g.getClassType();
				String attributeName = g.getAttributeName();
				ModuleContext context = new ModuleContext(getGoal().getContext(), classType.getKlass().getModule());
				subgoals.add(new ClassAttributeTypeGoal(context, classType, attributeName));
			}	<commit_msg>Comment<commit_after>/*
 * Copyright (C) 2007-2008  <NAME>, <NAME>
 *
 * IFS Institute for Software, HSR Rapperswil, Switzerland
 *
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
 *
 */

package ch.hsr.ifs.pystructure.typeinference.evaluators.types;

import java.util.ArrayList;
import java.util.List;

import org.python.pydev.parser.jython.ast.Attribute;

import ch.hsr.ifs.pystructure.typeinference.basetype.CombinedType;
import ch.hsr.ifs.pystructure.typeinference.basetype.IType;
import ch.hsr.ifs.pystructure.typeinference.contexts.ModuleContext;
import ch.hsr.ifs.pystructure.typeinference.evaluators.base.AbstractEvaluator;
import ch.hsr.ifs.pystructure.typeinference.goals.base.GoalState;
import ch.hsr.ifs.pystructure.typeinference.goals.base.IGoal;
import ch.hsr.ifs.pystructure.typeinference.goals.types.ClassAttributeTypeGoal;
import ch.hsr.ifs.pystructure.typeinference.goals.types.DefinitionTypeGoal;
import ch.hsr.ifs.pystructure.typeinference.goals.types.ExpressionTypeGoal;
import ch.hsr.ifs.pystructure.typeinference.goals.types.ResolveMethodGoal;
import ch.hsr.ifs.pystructure.typeinference.model.base.NodeUtils;
import ch.hsr.ifs.pystructure.typeinference.model.definitions.Class;
import ch.hsr.ifs.pystructure.typeinference.model.definitions.Definition;
import ch.hsr.ifs.pystructure.typeinference.model.definitions.Module;
import ch.hsr.ifs.pystructure.typeinference.model.definitions.Package;
import ch.hsr.ifs.pystructure.typeinference.model.definitions.PathElement;
import ch.hsr.ifs.pystructure.typeinference.results.types.ClassType;
import ch.hsr.ifs.pystructure.typeinference.results.types.ModuleType;
import ch.hsr.ifs.pystructure.typeinference.results.types.PackageType;

/**
 * Evaluator for the type of an attribute node. For example, the result for
 * <code>instance.method</code> would be the method.
 */
public class AttributeTypeEvaluator extends AbstractEvaluator {

	private final Attribute attribute;

	private CombinedType resultType;

	public AttributeTypeEvaluator(ExpressionTypeGoal goal, Attribute attribute) {
		super(goal);
		this.attribute = attribute;

		this.resultType = goal.resultType;
	}

	@Override
	public List<IGoal> init() {
		return wrap(new ExpressionTypeGoal(getGoal().getContext(), attribute.value));
	}

	@Override
	public List<IGoal> subgoalDone(IGoal subgoal, GoalState state) {
		if (state == GoalState.RECURSIVE) {
			// RECURSIVE could mean something like that:
			//   self.attr = self.attr
			// This doesn't add anything to the result type, so we ignore it.
			return IGoal.NO_GOALS;
		}
		
		List<IGoal> subgoals = new ArrayList<IGoal>();
		
		if (subgoal instanceof ExpressionTypeGoal) {
			ExpressionTypeGoal g = (ExpressionTypeGoal) subgoal;
			
			String attributeName = NodeUtils.getId(attribute.attr);
			for (IType type : g.resultType) {
				if (type instanceof ClassType) {
					// It's either a method or an attribute
					ClassType classType = (ClassType) type;
					Class klass = classType.getKlass();
	
					if (klass != null) {
						ModuleContext context = new ModuleContext(getGoal().getContext(), klass.getModule());
						subgoals.add(new ResolveMethodGoal(context, classType, attributeName));
					} else {
						/* klass is null, this probably means that we are talking about 
						 * an internal or unknown class */
					}
					
				} else if (type instanceof PackageType) {
					PackageType pkgType = (PackageType) type;
	
					Package pkg = pkgType.getPackage();
	
					PathElement child = pkg.getChild(attributeName);
	
					if (child != null) {
	
						if (child instanceof Package) {
							resultType.appendType(new PackageType((Package) child));
						} else if (child instanceof Module) {
							resultType.appendType(new ModuleType((Module) child));
						} else {
							throw new RuntimeException("Got SysPath, evil!");
						}
					} else {
						System.err.println("Unable to find " + attributeName + " in package " + pkg);
//						throw new RuntimeException("Unable to find " + attributeName + " in package " + pkg);
					}
					
				} else if (type instanceof ModuleType) {
					ModuleType moduleType = (ModuleType) type;
					Module module = moduleType.getModule();
	
					List<Definition> definitions = module.getDefinitions(attributeName);
					for (Definition definition : definitions) {
						ModuleContext context = new ModuleContext(getGoal().getContext(), module);
						subgoals.add(new DefinitionTypeGoal(context, definition));
					}
				}
				
				// TODO: PythonMetaclassType
			}
			
		} else if (subgoal instanceof ClassAttributeTypeGoal) {
			ClassAttributeTypeGoal g = (ClassAttributeTypeGoal) subgoal;
			resultType.appendType(g.resultType);
		
		} else if (subgoal instanceof ResolveMethodGoal) {
			ResolveMethodGoal g = (ResolveMethodGoal) subgoal;
			
			if (!g.methodTypes.isEmpty()) {
				resultType.appendType(g.methodTypes);
			} else {
				/* If we can't find a method with this name (both in the actual class
				 * and in the hierarchy we are trying to look for a class attribute 
				 */
				ClassType classType = g.getClassType();
				String attributeName = g.getAttributeName();
				ModuleContext context = new ModuleContext(getGoal().getContext(), classType.getKlass().getModule());
				subgoals.add(new ClassAttributeTypeGoal(context, classType, attributeName));
			}	
{'fraction_non_alphanumeric': 0.09929257200606367, 'fraction_numerical': 0.0035371399696816574, 'mean_word_length': 4.05965061780997, 'pattern_counts': {'":': 0, '<': 21, '<?xml version=': 0, '>': 21, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '4944340', 'n_tokens_mistral': 4142, 'n_tokens_neox': 3483, 'n_words': 916}