package org.eclipse.dltk.tcl.internal.core.codeassist; import java.util.ArrayList; 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.dltk.ast.ASTNode; import org.eclipse.dltk.ast.ASTVisitor; import org.eclipse.dltk.ast.declarations.FieldDeclaration; 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.statements.Block; import org.eclipse.dltk.core.DLTKCore; import org.eclipse.dltk.core.IField; import org.eclipse.dltk.core.IModelElement; import org.eclipse.dltk.core.IParent; import org.eclipse.dltk.core.IScriptProject; import org.eclipse.dltk.core.ISourceModule; import org.eclipse.dltk.core.IType; import org.eclipse.dltk.core.ModelException; import org.eclipse.dltk.tcl.ast.TclStatement; import org.eclipse.dltk.tcl.core.TclParseUtil; import org.eclipse.dltk.tcl.core.ast.TclPackageDeclaration; import org.eclipse.dltk.tcl.internal.core.packages.TclBuildPathPackageCollector; import org.eclipse.dltk.tcl.internal.core.search.mixin.TclMixinModel; import org.eclipse.dltk.tcl.internal.core.search.mixin.model.TclPackage; import org.eclipse.dltk.tcl.internal.parser.OldTclParserUtils; public class TclResolver { private IResolveElementParent resolver; private ModuleDeclaration moduleDeclaration; private ISourceModule sourceModule; public TclResolver(ISourceModule sourceModule, ModuleDeclaration moduleDeclaration, IResolveElementParent resolver) { this(sourceModule, moduleDeclaration); this.resolver = resolver; } public TclResolver(ISourceModule sourceModule, ModuleDeclaration moduleDeclaration) { this.sourceModule = sourceModule; this.moduleDeclaration = moduleDeclaration; } public IModelElement findModelElementFrom(ASTNode node) { List statements = moduleDeclaration.getStatements(); List elements = new ArrayList(); searchAddElementsTo(statements, node, sourceModule, elements); if (elements.size() == 1) { return (IModelElement) elements.get(0); } return null; } public interface IResolveElementParent { IModelElement findElementParent(ASTNode node, String name, IParent parent); } public void searchAddElementsTo(List statements, final ASTNode node, IParent element, List<IModelElement> selectionElements) { if (statements == null || element == null) { return; } Iterator i = statements.iterator(); while (i.hasNext()) { ASTNode nde = (ASTNode) i.next(); if (nde.equals(node)) { if (node instanceof MethodDeclaration) { String oName = ((MethodDeclaration) node).getName(); if (oName.indexOf("::") != -1) { String pName = oName.substring(0, oName.lastIndexOf("::")); pName = pName.replaceAll("::", "\\$"); if (pName.startsWith("$")) { if (pName.equals("$")) { element = sourceModule; } else { try { element = findTypeFrom( sourceModule.getChildren(), "", pName, '$'); } catch (ModelException e) { if (DLTKCore.DEBUG) { e.printStackTrace(); } } } } else { pName = "$" + pName; try { element = findTypeFrom(element.getChildren(), "", pName, '$'); if (element == null) { return; } } catch (ModelException e) { e.printStackTrace(); return; } } } } String nodeName = getNodeChildName(node); if (nodeName != null) { IModelElement e = null; if (nodeName.startsWith("::")) { nodeName = nodeName.substring(2); e = findChildrenByName(nodeName, sourceModule); } else { e = findChildrenByName(nodeName, element); } if (e == null && resolver != null) { e = resolver.findElementParent(node, nodeName, element); } if (e != null) { for (Iterator<IModelElement> k = selectionElements .iterator(); k.hasNext();) { final IModelElement ke = k.next(); if (nodeName.equals(ke.getElementName())) { k.remove(); } } selectionElements.add(e); } } return; } if (nde.sourceStart() <= node.sourceStart() && node.sourceEnd() <= nde.sourceEnd()) { if (nde instanceof TypeDeclaration) { TypeDeclaration type = (TypeDeclaration) nde; String typeName = getNodeChildName(type); IModelElement e = findChildrenByName(typeName, element); if (e == null && type.getName().startsWith("::")) { try { e = (IModelElement) findTypeFrom( sourceModule.getChildren(), "", type.getName().replaceAll("::", "\\$"), '$'); } catch (ModelException e1) { // TODO Auto-generated catch block e1.printStackTrace(); } } if (e instanceof IParent) { // was: if (e != null || e instanceof IParent) List stats = ((TypeDeclaration) nde).getStatements(); searchAddElementsTo(stats, node, (IParent) e, selectionElements); } } else if (nde instanceof MethodDeclaration) { searchInMethod(node, element, nde, selectionElements); } /* * else if (nde instanceof TclStatement) { TclStatement s = * (TclStatement) nde; Expression commandId = s.getAt(0); * final IParent e = element; if (commandId != null && * commandId instanceof SimpleReference) { String qname = * ((SimpleReference) commandId) .getName(); } } */ else { final IParent e = element; List statements2 = findExtractBlocks(nde); if (statements2.size() > 0) { searchAddElementsTo(statements2, node, e, selectionElements); } } return; } } } public static IModelElement findChildrenByName(String childName, IParent element) { try { if (element == null) { return null; } String nextName = null; int pos; if ((pos = childName.indexOf("::")) != -1) { nextName = childName.substring(pos + 2); // childName = ""; String[] split = TclParseUtil.tclSplit(childName); if (split.length > 0) { childName = split[0]; } } IModelElement[] children = element.getChildren(); if (children != null) { for (int i = 0; i < children.length; ++i) { String name = children[i].getElementName(); if (children[i] instanceof IField && name.indexOf('(') != -1) { name = name.substring(0, name.indexOf('(')); } if (name.equals(childName)) { if (nextName == null) { return children[i]; } else if (children[i] instanceof IParent) { return findChildrenByName(nextName, (IParent) children[i]); } } } } } catch (ModelException e) { if (DLTKCore.DEBUG) { e.printStackTrace(); } } return null; } public static IParent findTypeFrom(IModelElement[] childs, String name, String parentName, char delimiter) { try { for (int i = 0; i < childs.length; ++i) { if (childs[i] instanceof IType) { // if ((((IType) childs[i]).getFlags() & // Modifiers.AccNameSpace) == 0) { // continue; // } IType type = (IType) childs[i]; String qname = name + delimiter + type.getElementName(); if (qname.equals(parentName)) { return type; } IParent val = findTypeFrom(type.getChildren(), qname, parentName, delimiter); if (val != null) { return val; } } } } catch (ModelException e) { if (DLTKCore.DEBUG) { e.printStackTrace(); } } return null; } public static String getNodeChildName(ASTNode node) { if (node instanceof MethodDeclaration) { MethodDeclaration method = (MethodDeclaration) node; String name = method.getName(); if (name.indexOf("::") != -1) { return name.substring(name.lastIndexOf("::") + 2); } return name; } else if (node instanceof TypeDeclaration) { TypeDeclaration type = (TypeDeclaration) node; String name = type.getName(); /* * if (name.startsWith("::")) { return name.substring(2); } */ return name; } else if (node instanceof TclStatement) { String[] var = OldTclParserUtils .returnVariable((TclStatement) node); if (var != null) { return var[0]; } } else if (node instanceof FieldDeclaration) { return ((FieldDeclaration) node).getName(); } return null; } public void searchInMethod(final ASTNode node, IParent element, ASTNode nde, List selectionElements) { MethodDeclaration method = (MethodDeclaration) nde; String methodName = method.getName(); if (methodName.indexOf("::") != -1) { String pName = methodName.substring(0, methodName.lastIndexOf("::")); pName = pName.replaceAll("::", "\\$"); if (pName.equals("$")) { element = sourceModule; } else { try { element = TclResolver.findTypeFrom( sourceModule.getChildren(), "", pName, '$'); if (element == null) { return; } } catch (ModelException e) { e.printStackTrace(); return; } } methodName = TclResolver.getNodeChildName(nde); } else { if (method.getDeclaringTypeName() != null) { String pName = method.getDeclaringTypeName(); if (!pName.startsWith("::")) { pName = "$" + pName; } pName = pName.replaceAll("::", "\\$"); if (pName.equals("$")) { element = sourceModule; } else { try { element = TclResolver.findTypeFrom( sourceModule.getChildren(), "", pName, '$'); if (element == null) { return; } } catch (ModelException e) { e.printStackTrace(); return; } } methodName = TclResolver.getNodeChildName(nde); } } IModelElement e = TclResolver.findChildrenByName(methodName, element); if (e != null && e instanceof IParent) { List stats = ((MethodDeclaration) nde).getStatements(); searchAddElementsTo(stats, node, (IParent) e, selectionElements); } } public static List findExtractBlocks(ASTNode node) { final List statements2 = new ArrayList(); ASTVisitor visitor = new ASTVisitor() { @Override public boolean visit(Expression s) throws Exception { if (s instanceof Block) { statements2.addAll(((Block) s).getStatements()); } return super.visit(s); } }; try { node.traverse(visitor); } catch (Exception e) { if (DLTKCore.DEBUG) { e.printStackTrace(); } } return statements2; } public static List processReferenceModules(List packages, IScriptProject scriptProject) { Set allModules = new HashSet(); List orderedModules = new ArrayList(); // IInterpreterInstall install = null; // try { // install = ScriptRuntime.getInterpreterInstall(scriptProject); // } catch (CoreException e1) { // if (DLTKCore.DEBUG) { // e1.printStackTrace(); // } // } // List required = null; // if (install != null) { // required = new ArrayList(); // Set req = new HashSet(required); // for (Iterator iterator = packages.iterator(); iterator.hasNext();) { // String pkg = (String) iterator.next(); // required.add(pkg); // Set dependencies = PackagesManager.getInstance() // .getDependencies(pkg, install).keySet(); // for (Iterator iterator2 = dependencies.iterator(); iterator2 // .hasNext();) { // String depPkg = (String) iterator2.next(); // if (req.add(depPkg)) { // required.add(depPkg); // } // } // } // } else { // required = packages; // } List required = packages; // We need to look for all required packages from selected // module for (Iterator iterator2 = required.iterator(); iterator2.hasNext();) { String requiredPackage = (String) iterator2.next(); String pattern = TclPackage.makeSearchRequest(TclPackage.PROVIDE, requiredPackage); org.eclipse.dltk.core.ISourceModule[] modules = TclMixinModel .getInstance().getMixin(scriptProject).findModules(pattern); for (int i = 0; i < modules.length; i++) { String name = modules[i].getElementName(); if (name.equalsIgnoreCase("pkgindex.tcl") || name.equalsIgnoreCase("tclindex")) { // allModules.add(modules[i]); // This is package we need to add all files from it. IParent parent = (IParent) modules[i].getParent(); try { IModelElement[] children = parent.getChildren(); for (int j = 0; j < children.length; j++) { IModelElement child = children[j]; if (allModules.add(child)) { orderedModules.add(child); } } } catch (ModelException e) { if (DLTKCore.DEBUG) { e.printStackTrace(); } } } else { if (allModules.add(modules[i])) { orderedModules.add(modules[i]); } } } } return orderedModules; } /** * Filter similar elements with "package require in current module" * * @param elements * @return */ public static IModelElement[] complexFilter(IModelElement[] elements, IScriptProject scriptProject, TclBuildPathPackageCollector packageCollector, boolean allVariantsOnFailed) { if (elements == null || elements.length == 0) { return new IModelElement[0]; } Map similars = new HashMap(); // Obtain duplicate named elements for (int i = 0; i < elements.length; i++) { IModelElement element = elements[i]; String fullyQualifiedName = TclParseUtil .getFQNFromModelElement(element, "::"); if (similars.containsKey(fullyQualifiedName)) { List similar = (List) similars.get(fullyQualifiedName); similar.add(element); } else { List similar = new ArrayList(); similar.add(element); similars.put(fullyQualifiedName, similar); } } boolean processRequire = false; List result = new ArrayList(); List allModules = null; // Filter similar elements for (Iterator iterator = similars.values().iterator(); iterator .hasNext();) { List similar = (List) iterator.next(); if (similar.size() == 1) { result.add(similar.get(0)); } else { if (processRequire == false) { processRequire = true; // We need to choose one element. List directives = packageCollector.getRequireDirectives(); // We need a reordered list of packages List required = new ArrayList(); for (Iterator iterator2 = directives.iterator(); iterator2 .hasNext();) { TclPackageDeclaration decl = (TclPackageDeclaration) iterator2 .next(); required.add(decl.getName()); } allModules = TclResolver.processReferenceModules(required, scriptProject); } if (allModules != null) { IModelElement found = null; int index = -1; for (Iterator iterator2 = similar.iterator(); iterator2 .hasNext();) { IModelElement element = (IModelElement) iterator2 .next(); ISourceModule module = (ISourceModule) element .getAncestor(IModelElement.SOURCE_MODULE); int indexOf = allModules.indexOf(module); if (indexOf != -1) { // Found if (indexOf > index) { found = element; index = indexOf; } } } if (found == null) { if (allVariantsOnFailed) { result.addAll(similar); } else { result.add(similar.get(0)); } } else { result.add(found); } } } } return (IModelElement[]) result .toArray(new IModelElement[result.size()]); } }