| /******************************************************************************* |
| * 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; |
| } |
| } |
| |
| } |