blob: 3a1333d50418f05fb1ad2ece4ba3cd40b5687614 [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2005, 2017 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.ti;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IConfigurationElement;
import org.eclipse.core.runtime.IExtension;
import org.eclipse.core.runtime.IExtensionPoint;
import org.eclipse.core.runtime.Platform;
import org.eclipse.dltk.core.IScriptProject;
import org.eclipse.dltk.core.IType;
import org.eclipse.dltk.core.ModelException;
import org.eclipse.dltk.core.index2.search.ISearchEngine.MatchRule;
import org.eclipse.dltk.core.index2.search.ModelAccess;
import org.eclipse.dltk.core.search.IDLTKSearchConstants;
import org.eclipse.dltk.core.search.IDLTKSearchScope;
import org.eclipse.dltk.core.search.SearchEngine;
import org.eclipse.dltk.core.search.SearchPattern;
import org.eclipse.dltk.core.search.TypeNameMatch;
import org.eclipse.dltk.core.search.TypeNameMatchRequestor;
import org.eclipse.dltk.evaluation.types.AmbiguousType;
import org.eclipse.dltk.evaluation.types.UnknownType;
import org.eclipse.dltk.ti.goals.AbstractTypeGoal;
import org.eclipse.dltk.ti.types.IEvaluatedType;
public class DLTKTypeInferenceEngine implements ITypeInferencer {
private static final String NATURE = "nature"; //$NON-NLS-1$
private static final String TYPE_EVALUATORS = "org.eclipse.dltk.core.typeEvaluators"; //$NON-NLS-1$
private final static Map evaluatorsByNatures = new HashMap();
static {
IExtensionPoint extensionPoint = Platform.getExtensionRegistry()
.getExtensionPoint(TYPE_EVALUATORS);
IExtension[] ext = extensionPoint.getExtensions();
// ArrayList resolvers = new ArrayList();
for (int a = 0; a < ext.length; a++) {
IConfigurationElement[] elements = ext[a]
.getConfigurationElements();
IConfigurationElement myElement = elements[0];
try {
String nature = myElement.getAttribute(NATURE);
List list = (List) evaluatorsByNatures.get(nature);
if (list == null) {
list = new ArrayList();
evaluatorsByNatures.put(nature, list);
}
// ITypeInferencer resolver = (ITypeInferencer) myElement
// .createExecutableExtension("evaluator");
// resolvers.add(resolver);
// list.add(resolver);
list.add(myElement);
} catch (Exception e) {
e.printStackTrace();
}
}
}
public DLTKTypeInferenceEngine() {
}
private void flattenTypes(AmbiguousType type, Set typeSet) {
IEvaluatedType[] possibleTypes = type.getPossibleTypes();
for (int cnt = 0, max = possibleTypes.length; cnt < max; cnt++) {
if (possibleTypes[cnt] instanceof AmbiguousType) {
flattenTypes((AmbiguousType) possibleTypes[cnt], typeSet);
} else {
typeSet.add(possibleTypes[cnt]);
}
}
}
private void searchTypeDeclarations(IScriptProject dltkProject,
String patternString, final Set typeSet) {
try {
int includeMask = IDLTKSearchScope.SOURCES;
includeMask |= (IDLTKSearchScope.APPLICATION_LIBRARIES
| IDLTKSearchScope.REFERENCED_PROJECTS
| IDLTKSearchScope.SYSTEM_LIBRARIES);
IDLTKSearchScope scope = SearchEngine.createSearchScope(dltkProject,
includeMask);
String typeName = ""; //$NON-NLS-1$
if (patternString.indexOf("::") != -1) { //$NON-NLS-1$
typeName = patternString
.substring(patternString.indexOf("::") + 2); //$NON-NLS-1$
} else {
typeName = patternString;
}
// Search using new indexing infrastructure:
IType[] types = new ModelAccess().findTypes(typeName,
MatchRule.EXACT, 0, 0, scope, null);
if (types != null) {
typeSet.addAll(Arrays.asList(types));
} else {
// Fallback to old indexing engine:
TypeNameMatchRequestor requestor = new TypeNameMatchRequestor() {
@Override
public void acceptTypeNameMatch(TypeNameMatch match) {
typeSet.add(match.getType());
}
};
SearchEngine engine = new SearchEngine();
engine.searchAllTypeNames(null, 0, typeName.toCharArray(),
SearchPattern.R_EXACT_MATCH, IDLTKSearchConstants.TYPE,
scope, requestor,
IDLTKSearchConstants.WAIT_UNTIL_READY_TO_SEARCH, null);
}
} catch (CoreException cxcn) {
cxcn.printStackTrace();
}
}
private void collectSuperClasses(IScriptProject project, String typeName,
Set superClassSet) {
Set typeSet = new HashSet();
searchTypeDeclarations(project, typeName, typeSet);
if (typeSet.isEmpty() != true) {
IType itype;
String[] superClasses;
for (Iterator typeIter = typeSet.iterator(); typeIter.hasNext();) {
itype = (IType) typeIter.next();
if (itype.exists()) {
try {
superClasses = itype.getSuperClasses();
if (superClasses != null) {
for (int cnt = 0, max = superClasses.length; cnt < max; cnt++) {
if (!superClassSet
.contains(superClasses[cnt])) {
superClassSet.add(superClasses[cnt]);
collectSuperClasses(project,
superClasses[cnt], superClassSet);
}
}
}
} catch (ModelException mxcn) {
mxcn.printStackTrace();
}
}
}
}
}
private void reduceTypes(BasicContext context, Set typeSet) {
IEvaluatedType type;
Set superClassSet = new HashSet();
for (Iterator iter = typeSet.iterator(); iter.hasNext();) {
type = (IEvaluatedType) iter.next();
collectSuperClasses(context.getSourceModule().getScriptProject(),
type.getTypeName(), superClassSet);
}
if (!superClassSet.isEmpty()) {
for (Iterator iter = typeSet.iterator(); iter.hasNext();) {
type = (IEvaluatedType) iter.next();
if (superClassSet.contains(type.getTypeName())) {
iter.remove();
}
}
}
}
private static ThreadLocal<List<AbstractTypeGoal>> goals = new ThreadLocal<List<AbstractTypeGoal>>() {
@Override
protected List<AbstractTypeGoal> initialValue() {
return new ArrayList<>();
}
};
@Override
public IEvaluatedType evaluateType(AbstractTypeGoal goal, int time) {
String nature = goal.getContext().getLangNature();
List list = (List) evaluatorsByNatures.get(nature);
if (list != null) {
final List<AbstractTypeGoal> threadGoals = goals.get();
if (threadGoals.size() > 32) {
return null;
}
threadGoals.add(goal);
try {
return evaluateType(goal, time, list);
} finally {
threadGoals.remove(threadGoals.size() - 1);
}
}
return null;
}
private IEvaluatedType evaluateType(AbstractTypeGoal goal, int time,
List list) {
Set typeSet = new HashSet();
for (Iterator iterator = list.iterator(); iterator.hasNext();) {
IConfigurationElement element = (IConfigurationElement) iterator
.next();
ITypeInferencer ti;
try {
ti = (ITypeInferencer) element
.createExecutableExtension("evaluator"); //$NON-NLS-1$
} catch (CoreException e) {
e.printStackTrace();
continue;
}
// ITypeInferencer ti = (ITypeInferencer)
// iterator.next();
IEvaluatedType type = ti.evaluateType(goal, time);
if (type != null && !(type instanceof UnknownType)) {
if (type instanceof AmbiguousType) {
flattenTypes((AmbiguousType) type, typeSet);
} else {
typeSet.add(type);
}
}
}
if ((typeSet.size() > 1)
&& (goal.getContext() instanceof BasicContext)) {
reduceTypes((BasicContext) goal.getContext(), typeSet);
}
if (typeSet.size() == 1) {
return (IEvaluatedType) typeSet.iterator().next();
} else if (typeSet.size() > 1) {
return new AmbiguousType((IEvaluatedType[]) typeSet
.toArray(new IEvaluatedType[typeSet.size()]));
} else {
return null;
}
}
}