package org.eclipse.dltk.itcl.internal.core.search; import java.util.ArrayList; import java.util.Iterator; import java.util.List; import org.eclipse.dltk.ast.ASTNode; import org.eclipse.dltk.ast.declarations.FieldDeclaration; 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.references.SimpleReference; import org.eclipse.dltk.core.DLTKCore; 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.core.mixin.IMixinElement; import org.eclipse.dltk.core.mixin.IMixinRequestor; import org.eclipse.dltk.itcl.internal.core.IncrTclResolver; import org.eclipse.dltk.itcl.internal.core.parser.IncrTclCommandDetector.IncrTclGlobalClassParameter; import org.eclipse.dltk.itcl.internal.core.parser.ast.IncrTclBodyDeclaration; import org.eclipse.dltk.itcl.internal.core.parser.ast.IncrTclExInstanceVariable; import org.eclipse.dltk.itcl.internal.core.parser.ast.IncrTclInstanceVariable; import org.eclipse.dltk.itcl.internal.core.parser.ast.IncrTclMethodCallStatement; import org.eclipse.dltk.itcl.internal.core.parser.ast.IncrTclMethodDeclaration; import org.eclipse.dltk.itcl.internal.core.search.mixin.model.IncrTclInstProc; import org.eclipse.dltk.tcl.ast.TclStatement; import org.eclipse.dltk.tcl.core.TclParseUtil; import org.eclipse.dltk.tcl.core.ast.ExtendedTclMethodDeclaration; import org.eclipse.dltk.tcl.core.extensions.ISelectionExtension; import org.eclipse.dltk.tcl.internal.core.codeassist.TclResolver; import org.eclipse.dltk.tcl.internal.core.codeassist.TclSelectionEngine; import org.eclipse.dltk.tcl.internal.core.codeassist.selection.SelectionOnKeywordOrFunction; import org.eclipse.dltk.tcl.internal.core.search.mixin.TclMixinModel; public class IncrTclSelectionExtension implements ISelectionExtension { @Override public void selectionOnKeywordOrFunction(SelectionOnKeywordOrFunction key, TclSelectionEngine engine) { ASTNode originalNode = key.getOriginalNode(); if (originalNode instanceof TclStatement) { processIncrTclCommandCalls((TclStatement) originalNode, engine); } } private void processIncrTclInstanceVariable(IncrTclInstanceVariable node, TclSelectionEngine engine) { SimpleReference classInstanceName = node.getClassInstanceName(); if (classInstanceName.sourceStart() <= engine.getActualSelectionStart() && engine.getActualSelectionStart() <= classInstanceName.sourceEnd()) { TypeDeclaration declaringType = node.getDeclaringType(); IModelElement type = engine.findElementFromNode(declaringType); if (type != null) { engine.addSelectionElement(type); } } } private void processIncrTclCommandCalls(TclStatement node, TclSelectionEngine engine) { // System.out.println("CoOL:" + node); if (node.getCount() == 0) { return; } ASTNode parent = TclParseUtil.getPrevParent(engine.getAssistParser().getModule(), node); String prefix = TclParseUtil.getElementFQN(parent, IMixinRequestor.MIXIN_NAME_SEPARATOR, engine.getAssistParser().getModule()); Expression commandExpr = node.getAt(0); String command = TclParseUtil.getNameFromNode(commandExpr); if ("$this".equals(command)) { ASTNode scopeParent = TclParseUtil.getScopeParent(engine.getAssistParser().getModule(), node); if (scopeParent instanceof IncrTclMethodDeclaration) { IncrTclMethodDeclaration method = (IncrTclMethodDeclaration) scopeParent; ASTNode type = method.getDeclaringType(); TclResolver resolver = new TclResolver((ISourceModule) engine.getSourceModule(), engine.getAssistParser().getModule()); IModelElement typeElement = resolver.findModelElementFrom(type); if (commandExpr.sourceStart() <= engine.getActualSelectionStart() && engine.getActualSelectionStart() <= commandExpr.sourceEnd()) { engine.addSelectionElement(typeElement); } if (node.getCount() > 1) { ASTNode callExpr = node.getAt(1); if (callExpr.sourceStart() <= engine.getActualSelectionStart() && engine.getActualSelectionStart() <= callExpr.sourceEnd() && callExpr instanceof SimpleReference && typeElement instanceof IParent) { SimpleReference callName = (SimpleReference) callExpr; IModelElement child = TclResolver.findChildrenByName(callName.getName(), (IParent) typeElement); if (child != null) { engine.addSelectionElement(child); } } } // TclResolver.findChildrenByName(, null) } } if (command != null && command.startsWith("::")) { String name = command.substring(2); // Check class proc call String[] split = TclParseUtil.tclSplit(name); IModelElement[] typeMixin = IncrTclResolver.findTypeMixin(engine.tclNameToKey(name), split[split.length - 1], engine.getScriptProject()); checkMixinTypeForMethod(node, commandExpr, typeMixin, prefix, engine); } else if (command != null) { String[] split = TclParseUtil.tclSplit(command); if (parent instanceof ModuleDeclaration) { IModelElement[] typeMixin = IncrTclResolver.findTypeMixin(engine.tclNameToKey(command), split[split.length - 1], engine.getScriptProject()); checkMixinTypeForMethod(node, commandExpr, typeMixin, prefix, engine); } else { IModelElement[] typeMixin = IncrTclResolver.findTypeMixin( prefix + IMixinRequestor.MIXIN_NAME_SEPARATOR + engine.tclNameToKey(command), split[split.length - 1], engine.getScriptProject()); checkMixinTypeForMethod(node, commandExpr, typeMixin, prefix, engine); } } } private boolean checkMixinTypeForMethod(TclStatement node, Expression commandExpr, IModelElement[] typeMixin, String prefix, TclSelectionEngine engine) { for (int i = 0; i < typeMixin.length; i++) { // Select type if point on type if (commandExpr.sourceStart() <= engine.getActualSelectionStart() && engine.getActualSelectionStart() <= commandExpr.sourceEnd()) { engine.addSelectionElement(typeMixin[i]); return true; } Expression callExpr = node.getAt(1); if (node.getCount() > 1 && typeMixin[i] instanceof IParent) { if (callExpr.sourceStart() <= engine.getActualSelectionStart() && engine.getActualSelectionStart() <= callExpr.sourceEnd()) { String call = TclParseUtil.getNameFromNode(callExpr); IParent eParent = (IParent) typeMixin[i]; if (call != null) { // search for method call in selected type IModelElement[] children = null; try { children = eParent.getChildren(); } catch (ModelException e) { // TODO Auto-generated catch block e.printStackTrace(); } if (children != null) { for (int j = 0; j < children.length; j++) { if (children[j].getElementType() == IModelElement.METHOD && children[j].getElementName().equals(call)) { engine.addSelectionElement(children[j]); return true; } } } // We need to check super type of this type. if (eParent instanceof IType) { IType type = (IType) eParent; try { String[] superClasses = type.getSuperClasses(); String command = TclParseUtil.getNameFromNode(commandExpr); if (superClasses != null) { for (int j = 0; j < superClasses.length; j++) { IModelElement[] ptypeMixin = IncrTclResolver.findTypeMixin( (prefix.length() > 0 ? prefix + IMixinRequestor.MIXIN_NAME_SEPARATOR : "") + engine.tclNameToKey(superClasses[j]), superClasses[j], engine.getScriptProject()); String[] split = TclParseUtil.tclSplit(superClasses[j]); checkMixinTypeForMethod(node, commandExpr, ptypeMixin, split[split.length - 1], engine); } } } catch (ModelException e) { if (DLTKCore.DEBUG) { e.printStackTrace(); } } } } } } } return false; } private void processSelectIncrTclMethodDeclaration(ExtendedTclMethodDeclaration node, int position, TclSelectionEngine engine) { ASTNode type = node.getDeclaringType(); if (type instanceof TypeDeclaration) { SimpleReference ref = node.getTypeNameRef(); IModelElement parent = engine.findElementFromNode(type); if (parent != null && parent instanceof IParent) { if (node.getNameStart() <= position && position <= node.getNameEnd()) { IModelElement methodElement = TclResolver.findChildrenByName(node.getName(), (IParent) parent); engine.addSelectionElement(methodElement); return; } else if (ref != null && ref.sourceStart() <= position && position <= ref.sourceEnd()) { engine.addSelectionElement(parent); } } } } private void processSelectIncrTclMethod(IncrTclMethodCallStatement call, int position, TclSelectionEngine engine) { FieldDeclaration instanceVar = call.getInstanceVariable(); SimpleReference callName = call.getCallName(); SimpleReference instName = call.getInstNameRef(); if (instanceVar != null && instanceVar instanceof IncrTclInstanceVariable) { // Check for method if (callName.sourceStart() <= position && position <= callName.sourceEnd()) { IncrTclInstanceVariable instanceVariable = (IncrTclInstanceVariable) instanceVar; TypeDeclaration declaringType = instanceVariable.getDeclaringType(); if (declaringType != null) { IModelElement parent = engine.findElementFromNode(declaringType); if (parent != null) { if (engine.checkMethodFrom(declaringType, callName, parent)) { return; } // Check mixin for selected class. String typeMixin = TclParseUtil.getElementFQN(declaringType, IMixinRequestor.MIXIN_NAME_SEPARATOR, engine.getAssistParser().getModule()) + IMixinRequestor.MIXIN_NAME_SEPARATOR; engine.findMethodMixin(typeMixin + engine.tclNameToKey(callName.getName()), callName.getName()); // Check super. ASTNode nde = TclParseUtil.getPrevParent(engine.getAssistParser().getModule(), declaringType); List supersToHandle = new ArrayList(); engine.fillSuperClassesTo(declaringType, supersToHandle); TypeDeclaration prev = declaringType; while (supersToHandle.size() > 0) { String superClassName = (String) supersToHandle.get(0); supersToHandle.remove(0); TypeDeclaration sType = TclParseUtil.findXOTclTypeDeclarationFrom( engine.getAssistParser().getModule(), nde, superClassName); if (sType != null) { prev = sType; engine.fillSuperClassesTo(sType, supersToHandle); IModelElement sParent = engine.findElementFromNode(sType); if (engine.checkMethodFrom(sType, callName, sParent)) { return; } String sTypeMixin = TclParseUtil.getElementFQN(sType, IMixinRequestor.MIXIN_NAME_SEPARATOR, engine.getAssistParser().getModule()) + IMixinRequestor.MIXIN_NAME_SEPARATOR; findIncrTclMethodMixin(sTypeMixin + engine.tclNameToKey(callName.getName()), callName.getName(), engine); // System.out.println("COOL"); } else { String sTypeMixin = ""; if (prev != null) { ASTNode prevParent = TclParseUtil .getPrevParent(engine.getAssistParser().getModule(), prev); if (prevParent instanceof ModuleDeclaration) { sTypeMixin = engine.tclNameToKey(superClassName) + IMixinRequestor.MIXIN_NAME_SEPARATOR; } else { sTypeMixin = TclParseUtil.getElementFQN(prevParent, IMixinRequestor.MIXIN_NAME_SEPARATOR, engine.getAssistParser().getModule()) + IMixinRequestor.MIXIN_NAME_SEPARATOR + engine.tclNameToKey(superClassName) + IMixinRequestor.MIXIN_NAME_SEPARATOR; } } findIncrTclMethodMixin(sTypeMixin + engine.tclNameToKey(callName.getName()), callName.getName(), engine); // Lets also look to toplevel findIncrTclMethodMixin( engine.tclNameToKey(superClassName) + IMixinRequestor.MIXIN_NAME_SEPARATOR + engine.tclNameToKey(callName.getName()), callName.getName(), engine); } } } } } } else if (instanceVar != null && instanceVar instanceof IncrTclExInstanceVariable) { // Check for method IncrTclExInstanceVariable instanceVariable = (IncrTclExInstanceVariable) instanceVar; IType type = (IType) instanceVariable.getDeclaringClassParameter().resolveElement(); if (type != null && (instName.sourceStart() <= position && position <= instName.sourceEnd())) { // Selection to field declaration engine.addElementFromASTNode(instanceVariable); } else if (type != null && callName.sourceStart() <= position && position <= callName.sourceEnd()) { String typeMixin = TclParseUtil.getFQNFromModelElement(type, "::"); if (typeMixin.startsWith("::")) { typeMixin = typeMixin.substring(2); } findIncrTclMethodMixin(engine.tclNameToKey(typeMixin) + IMixinRequestor.MIXIN_NAME_SEPARATOR + engine.tclNameToKey(callName.getName()), callName.getName(), engine); // Check super. List supersToHandle = new ArrayList(); String[] superClasses = null; try { superClasses = type.getSuperClasses(); } catch (ModelException e) { if (DLTKCore.DEBUG) { e.printStackTrace(); } } if (superClasses != null) { for (int i = 0; i < superClasses.length; i++) { supersToHandle.add(superClasses[i]); } } String prevClass = type.getFullyQualifiedName(); if (prevClass.startsWith("::")) { prevClass = prevClass.substring(2); } while (supersToHandle.size() > 0) { String superClassName = (String) supersToHandle.get(0); supersToHandle.remove(0); if (superClassName.startsWith("::")) { findIncrTclMethodMixin(superClassName.substring(2) + engine.tclNameToKey(callName.getName()), callName.getName(), engine); } else { // remove one level from prev class } } } } if (engine.getSelectionElementsSize() == 0) { if (instName.sourceStart() <= position && position <= instName.sourceEnd()) { engine.addElementFromASTNode(instanceVar); } } } private void findIncrTclMethodMixin(String pattern, String name, TclSelectionEngine engine) { IScriptProject project = engine.getScriptProject(); IMixinElement[] find = TclMixinModel.getInstance().getMixin(project).find(pattern + "*"); int pos = pattern.indexOf(IMixinRequestor.MIXIN_NAME_SEPARATOR); if (find.length == 0 && pos != -1) { String newPattern = pattern.substring(0, pos); find = TclMixinModel.getInstance().getMixin(project).find(newPattern + "*"); } for (int i = 0; i < find.length; i++) { Object[] allObjects = find[i].getAllObjects(); for (int j = 0; j < allObjects.length; j++) { if (allObjects[j] != null && allObjects[j] instanceof IncrTclInstProc) { IncrTclInstProc field = (IncrTclInstProc) allObjects[j]; if (name.equals(field.getName())) { engine.addSelectionElement(field.getModelElement()); return; } } } } } @Override public void selectionOnAST(ASTNode node, TclSelectionEngine engine) { if (node instanceof IncrTclMethodDeclaration) { processSelectIncrTclMethodDeclaration((ExtendedTclMethodDeclaration) node, engine.getActualSelectionStart(), engine); if (engine.getSelectionElementsSize() > 0) { return; } } } @Override public void selectionOnNode(ASTNode node, int position, TclSelectionEngine engine) { if (node instanceof IncrTclMethodCallStatement) { processSelectIncrTclMethod((IncrTclMethodCallStatement) node, position, engine); } else if (node instanceof IncrTclMethodDeclaration) { processSelectIncrTclMethodDeclaration((ExtendedTclMethodDeclaration) node, engine.getActualSelectionStart(), engine); } else if (node instanceof TclStatement) { // We need to check for XOTcl command calls. processIncrTclCommandCalls((TclStatement) node, engine); } else if (node instanceof IncrTclInstanceVariable) { processIncrTclInstanceVariable((IncrTclInstanceVariable) node, engine); } else if (node instanceof IncrTclExInstanceVariable) { IncrTclExInstanceVariable ex = (IncrTclExInstanceVariable) node; IncrTclGlobalClassParameter declaringClassParameter = ex.getDeclaringClassParameter(); IModelElement resolveElement = declaringClassParameter.resolveElement(); if (resolveElement != null) { engine.addSelectionElement(resolveElement); } } } @Override public IModelElement findElementParent(ASTNode node, String name, IParent parent, TclSelectionEngine engine) { if (node instanceof IncrTclBodyDeclaration) { IncrTclBodyDeclaration body = (IncrTclBodyDeclaration) node; ASTNode type = body.getDeclaringType(); if (parent instanceof IModelElement) { ISourceModule module = (ISourceModule) ((IModelElement) parent) .getAncestor(IModelElement.SOURCE_MODULE); TclResolver resolver = new TclResolver(module, engine.getAssistParser().getModule()); IModelElement parentElement = resolver.findModelElementFrom(type); if (parentElement != null && parentElement instanceof IParent) { return TclResolver.findChildrenByName(body.getName(), (IParent) parentElement); } } } return null; } @Override public void findVariables(String name, ASTNode parent, int beforePosition, TclSelectionEngine engine) { if (parent instanceof IncrTclMethodDeclaration) { if (name.startsWith("$")) { name = name.substring(1); } IncrTclMethodDeclaration method = (IncrTclMethodDeclaration) parent; TypeDeclaration type = (TypeDeclaration) method.getDeclaringType(); if (type != null) { List fieldList = type.getFieldList(); for (Iterator iterator = fieldList.iterator(); iterator.hasNext();) { FieldDeclaration field = (FieldDeclaration) iterator.next(); if (field.getName().equals(name)) { engine.addElementFromASTNode(field); } } } } } }