|
What this is
Other links
The source code/* * Sun Public License Notice * * The contents of this file are subject to the Sun Public License * Version 1.0 (the "License"). You may not use this file except in * compliance with the License. A copy of the License is available at * http://www.sun.com/ * * The Original Code is NetBeans. The Initial Developer of the Original * Code is Sun Microsystems, Inc. Portions Copyright 1997-2000 Sun * Microsystems, Inc. All Rights Reserved. */ package org.netbeans.modules.editor.java; import java.util.*; import java.lang.reflect.Modifier; import javax.swing.text.JTextComponent; import javax.swing.text.BadLocationException; import org.netbeans.editor.ext.CompletionQuery; import org.netbeans.editor.ext.ExtFormatter; import org.netbeans.editor.ext.Completion; import org.netbeans.editor.ext.ExtEditorUI; import org.netbeans.editor.ext.java.*; import org.netbeans.editor.BaseDocument; import org.netbeans.editor.Formatter; import org.netbeans.editor.Utilities; import org.netbeans.editor.TokenItem; import org.netbeans.jmi.javamodel.*; import org.netbeans.modules.editor.java.JMIUtils; /** * Java completion query working with java JMI interfaces. * * @author Dusan Balek * @version 1.00 */ public class NbJavaJMICompletionQuery extends NbJavaCompletionQuery { private static JMIItemFactory jmiItemFactory = new DefaultJMIItemFactory(); public NbJavaJMICompletionQuery(boolean isJava15) { setJava15(isJava15); } protected CompletionQuery.Result getResult(JTextComponent component, JavaSyntaxSupport sup, boolean openingSource, int offset, JCExpression exp) { Completion completion = ((ExtEditorUI)Utilities.getEditorUI(component)).getCompletion(); boolean autoPopup = completion != null ? completion.provokedByAutoPopup : false; JMIUtils utils = JMIUtils.get(getBaseDocument()); utils.beginTrans(false); try { Context ctx = new Context(component, (NbJavaJMISyntaxSupport)sup.get(NbJavaJMISyntaxSupport.class), openingSource, offset, utils, autoPopup); ctx.resolveExp(exp); return ctx.result; } finally { utils.endTrans(false); } } class Context { /** Text component */ private JTextComponent component; /** Syntax support for the given document */ private NbJavaJMISyntaxSupport sup; /** Whether the query is performed to open the source file. It has slightly * different handling in some situations. */ private boolean openingSource; /** End position of the scanning - usually the caret position */ private int endOffset; /** If set to true true - find the type of the result expression. * It's stored in the lastType variable or lastPkg if it's a package. * The result variable is not populated. * False means that the code completion output should be collected. */ private boolean findType; /** Whether currently scanning either the package or the class name * so the results should limit the search to the static fields and methods. */ private boolean staticOnly = true; /** Last package found when scanning dot expression */ private JavaPackage lastPkg; /** Last type found when scanning dot expression */ private Type lastType; /** Result list when code completion output is generated */ private JavaResult result; /** Helper flag for recognizing constructors */ private boolean isConstructor; private boolean isImport; private boolean isStaticImport; private boolean isGeneric; private Collection typeBounds; private boolean isAnnotation; private JavaClass curCls; private boolean isThisContext; private boolean superCall; /** True when code completion is invoked by auto popup. In such case, code completion returns no result * after "new ". To get a result, code completion has to be invoked manually (using Ctrl-Space). */ // NOI18N private boolean autoPopup; /** Finder associated with this Context. */ private JMIUtils jmiUtils = null; public Context(JTextComponent component, NbJavaJMISyntaxSupport sup, boolean openingSource, int endOffset, JMIUtils utils, boolean autoPopup) { this.component = component; this.sup = sup; this.openingSource = openingSource; this.endOffset = endOffset; this.jmiUtils = utils; this.curCls = sup.getJavaClass(endOffset); if (this.curCls == null) { this.curCls = sup.getTopJavaClass(); } this.autoPopup = autoPopup; } public void setFindType(boolean findType) { this.findType = findType; } protected Object clone() { return new Context(component, sup, openingSource, endOffset, jmiUtils, autoPopup); } private int getSwitchOffset(int caseOffset) { int offset = -1; try { JavaFormatSupport jfs = new JavaFormatSupport(null); TokenItem itm = jfs.findSwitch(sup.getTokenChain(caseOffset, caseOffset + 4)); if (itm != null) { int off = itm.getNext().getOffset(); off = Utilities.getFirstNonWhiteFwd(getBaseDocument(), off); int[] block = sup.findMatchingBlock(off, true); if (block != null) { offset = block[1] - 1; } } } catch (Exception e) { } return offset; } private String formatType(Type type, boolean useFullName, boolean appendDot, boolean appendStar) { StringBuffer sb = new StringBuffer(); if (type != null) { if (useFullName) { if (type instanceof ParameterizedType) { ClassDefinition decl = ((ParameterizedType)type).getDeclaringClass(); if (decl != null) { sb.append(formatType(decl, useFullName, true, false)); } else { String s = ((ParameterizedType)type).getDefinition().getName(); sb.append(s.substring(0, s.lastIndexOf('.') + 1)); } sb.append(((ParameterizedType)type).getSimpleName()); } else { sb.append(type.getName()); } } else { sb.append(type instanceof JavaClass ? ((JavaClass)type).getSimpleName() : type.getName()); } } if (appendDot) { sb.append('.'); // NOI18N } if (appendStar) { sb.append('*'); // NOI18N } return sb.toString(); } private Type resolveType(JCExpression exp, boolean propagateIsStatic) { Context ctx = (Context)clone(); ctx.setFindType(true); ctx.isGeneric = isGeneric; Type typ = null; if (ctx.resolveExp(exp)) { typ = ctx.lastType; if (propagateIsStatic) { staticOnly = ctx.staticOnly; } } if (JMIUtils.debugCompletionFailures && typ instanceof UnresolvedClass) { System.err.println("resolveType: unresolved type " + typ.getName() + " returned when resolving " + exp); // NOI18N Thread.dumpStack(); } return typ; } boolean resolveExp(JCExpression exp) { boolean lastDot = false; // dot at the end of the whole expression? boolean ok = true; switch (exp.getExpID()) { case JCExpression.DOT_OPEN: // Dot expression with the dot at the end lastDot = true; // let it flow to DOT case JCExpression.DOT: // Dot expression int parmCnt = exp.getParameterCount(); // Number of items in the dot exp for (int i = 0; i < parmCnt && ok; i++) { // resolve all items in a dot exp ok = resolveItem(exp.getParameter(i), (i == 0), (!lastDot && i == parmCnt - 1) ); isThisContext = superCall; superCall = false; if (JMIUtils.debugCompletionFailures && !ok) { System.err.println("resolveItem: failed when resolving " + exp.getParameter(i) + "\n lastType=" + lastType + "\n lastPkg=" + lastPkg); // NOI18N Thread.dumpStack(); } } if (ok && lastDot) { // Found either type or package help // Need to process dot at the end of the expression int tokenCntM1 = exp.getTokenCount() - 1; int substPos = exp.getTokenOffset(tokenCntM1) + exp.getTokenLength(tokenCntM1); if (lastType != null) { // Found type List res = new ArrayList(); if (openingSource) { res.add(lastType); } else if (!isConstructor && (!isImport || isStaticImport)){ // not source-help if (staticOnly && !isImport) res.add(getJMIItemFactory().createVarResultItem("class", jmiUtils.getExactClass("java.lang.Class"), Modifier.PUBLIC | Modifier.STATIC | Modifier.FINAL)); // NOI18N res.addAll(findFieldsMethodsAndInnerClasses(lastType, "", false, false, curCls, staticOnly || isStaticImport, isThisContext, exp, null, false)); // NOI18N } else { res.addAll(findInnerClasses(lastType, "", false, false, curCls, isThisContext, true, true)); } // Get all fields and methods of the cls result = new JavaResult(component, res, formatType(lastType, true, true, true), exp, substPos, 0, lastType instanceof JavaClass ? (JavaClass)lastType : curCls); } else { // Found package (otherwise ok would be false) String searchPkg = lastPkg.getName() + '.'; List res = new ArrayList(); if (openingSource) { res.add(lastPkg); // return only the package } else { if (isAnnotation) { res.addAll(jmiUtils.findAnnotations(lastPkg, "", false, curCls, false)); } else { String text = null; try { int firstTokenIdx = exp.getTokenOffset(0); int cmdStartIdx = sup.getLastCommandSeparator(firstTokenIdx); if (cmdStartIdx < 0) { text = sup.getDocument().getText(0, firstTokenIdx); cmdStartIdx = text.lastIndexOf(0x0A); if (cmdStartIdx != -1) { text = text.substring(cmdStartIdx + 1); } } else { text = sup.getDocument().getText(cmdStartIdx, firstTokenIdx - cmdStartIdx); } } catch (BadLocationException e) { // ignore and provide full list of items } if (text != null && -1 == text.indexOf("package")) { // NOI18N res.addAll(jmiUtils.findClasses(lastPkg, "", false, curCls, !isGeneric)); // package classes } } } res.addAll(jmiUtils.findPackages(searchPkg, false, false, !isGeneric)); // find all subpackages if (isGeneric) res = filterGenericTypeArguments(res); result = new JavaResult(component, res, (isAnnotation ? "@" : "") + searchPkg + '*', // NOI18N exp, substPos, 0, curCls); } } break; case JCExpression.NEW: // 'new' keyword if (!autoPopup) { List res = findInnerClasses(curCls, "", false, true, curCls, isThisContext, true, true); res.addAll(jmiUtils.findClasses(null, "", false, curCls, true)); // Find all classes by name // NOI18N result = new JavaResult(component, res, "*", exp, endOffset, 0, curCls); // NOI18N } break; case JCExpression.CASE: int off = getSwitchOffset(exp.getTokenOffset(0)); if (off > -1) { Result r = NbJavaJMICompletionQuery.this.query(component, off, sup, true); if (r != null && r.getData().size() > 0) { Object itm = r.getData().get(0); if (itm instanceof NbJMIResultItem) itm = ((NbJMIResultItem)itm).getAssociatedObject(); if (itm instanceof TypedElement) { Type typ = ((TypedElement)itm).getType(); if (typ instanceof ParameterizedType) typ = ((ParameterizedType)typ).getDefinition(); String name = ""; // NOI18N if (exp.getParameterCount() == 1) { JCExpression eexp = exp.getParameter(0); if (eexp.getExpID() == JCExpression.VARIABLE) name = eexp.getTokenText(0); } List res = typ instanceof JavaEnum ? jmiUtils.findEnumConstants((JavaEnum)typ, name, false, true) : Collections.EMPTY_LIST; result = new JavaResult(component, res, formatType(typ, true, false, false), exp, endOffset, 0, curCls); } } } break; default: // The rest of the situations is resolved as a singleton item ok = resolveItem(exp, true, true); break; } return ok; } /** Resolve one item from the expression connected by dots. * @param item expression item to resolve * @param first whether this expression is the first one in a dot expression * @param last whether this expression is the last one in a dot expression */ boolean resolveItem(JCExpression item, boolean first, boolean last) { boolean cont = true; // whether parsing should continue or not boolean methodOpen = false; // helper flag for unclosed methods switch (item.getExpID()) { case JCExpression.CONSTANT: // Constant item if (first) { lastType = jmiUtils.resolveType(item.getType()); // Get the constant type staticOnly = false; } else { // Not the first item in a dot exp cont = false; // impossible to have constant inside the expression } break; case JCExpression.VARIABLE: // Variable or special keywords switch (item.getTokenID(0).getNumericID()) { case JavaTokenContext.THIS_ID: // 'this' keyword if (first) { // first item in expression if (curCls != null) { lastType = curCls; staticOnly = false; } } else { // 'something.this' staticOnly = false; } break; case JavaTokenContext.SUPER_ID: // 'super' keyword if (first) { // only allowed as the first item JavaClass cls = curCls; if (cls != null) { cls = cls.getSuperClass(); if (cls != null) { lastType = cls; staticOnly = false; superCall = true; } } } else { cont = false; } break; case JavaTokenContext.CLASS_ID: // 'class' keyword if (!first) { lastType = jmiUtils.getExactClass("java.lang.Class"); // NOI18N staticOnly = false; } else { cont = false; } break; default: // Regular constant String var = item.getTokenText(0); int varPos = item.getTokenOffset(0); if (first) { // try to find variable for the first item if (last && !findType) { // both first and last item List res = new ArrayList(); if (isAnnotation) { res.addAll(jmiUtils.findAnnotations(null, var, openingSource, curCls, false)); } else if (curCls != null && !isGeneric && !isConstructor && !isImport) { Collection local = sup.getLocalVariableNames(var, varPos, openingSource); for (Iterator it = local.iterator(); it.hasNext();) { String name = (String) it.next(); Type t = (Type)sup.findType(name, varPos); if (t != null) res.add(getJMIItemFactory().createVarResultItem(name, t, 0)); } res.addAll(findFieldsMethodsAndInnerClasses(curCls, var, openingSource, true, curCls, sup.isStaticBlock(varPos), isThisContext, item, local, true)); res.addAll(findStaticallyImportedFeatures(var, openingSource, curCls, isThisContext)); // add static imports } if (var.length() > 0) { if (openingSource) { res.add(sup.getTypeFromName(var, true, curCls)); } else if (!isAnnotation) { if (isGeneric || isConstructor || isImport) res.addAll(findInnerClasses(curCls, var, false, true, curCls, isThisContext, !isGeneric, !isGeneric)); res.addAll(jmiUtils.findClasses(null, var, false, curCls, !isGeneric)); // add matching classes } } res.addAll(jmiUtils.findPackages(var, openingSource, false, true)); // add matching packages if (isGeneric) res = filterGenericTypeArguments(res); result = new JavaResult(component, res, (isAnnotation ? "@" : "") + var + '*', item, curCls); // NOI18N } else { // not last item or finding type lastType = (Type)sup.findType(var, varPos); if (lastType != null) { // variable found if (isGeneric) lastType = null; else staticOnly = false; if (JMIUtils.debugCompletionFailures && lastType instanceof UnresolvedClass) { System.err.println("resolveItem: unresolved type " + lastType.getName() + " returned when resolving type of variable " + var); // NOI18N Thread.dumpStack(); } } else { // no variable found lastPkg = jmiUtils.getExactPackage(var); // try package if (lastPkg == null) { // not package, let's try class name Type typ = sup.getTypeFromName(var, true, curCls); if (typ == null) { List sf = jmiUtils.getStaticallyImportedFields(var, true, curCls, isThisContext); if (sf.size() > 0) { typ = ((Field)sf.get(0)).getType(); staticOnly = false; } } if (typ != null) { lastType = typ; } else { // class not found cont = false; } } } } } else { // not the first item if (lastType != null) { // last was type if (findType || !last) { boolean inner = false; if (staticOnly && lastType instanceof JavaClass) { // can be inner class JavaClass cls = ((JavaClass)lastType).getInnerClass(var, true); // NOI18N if (cls != null) { lastType = cls; inner = true; } } if (!inner) { // not inner class name if (lastType instanceof JavaClass) { // zero array depth List fldList = jmiUtils.findFields(lastType, var, true, false, curCls, staticOnly, isThisContext, false, false); if (fldList.size() > 0) { // match found Field fld = (Field)fldList.get(0); lastType = fld.getType(); staticOnly = false; } else { // no match found lastType = null; cont = false; } } else { // array depth > 0 but no array dereference cont = false; } } } else { // last and searching for completion output List res = new ArrayList(); if (!isImport || isStaticImport) { if (!isImport && staticOnly && jmiUtils.startsWith("class", var)) // NOI18N res.add(getJMIItemFactory().createVarResultItem("class", jmiUtils.getExactClass("java.lang.Class"), Modifier.PUBLIC | Modifier.STATIC | Modifier.FINAL)); // NOI18N res.addAll(findFieldsMethodsAndInnerClasses(lastType, var, false, false, curCls, staticOnly || isStaticImport, isThisContext, item, null, false)); } else { res.addAll(findInnerClasses(lastType, var, false, false, curCls, isThisContext, true, true)); } result = new JavaResult( component, res, formatType(lastType, false, true, false) + var + '*', item, lastType instanceof JavaClass ? (JavaClass)lastType : curCls); } } else { // currently package String searchName = lastPkg.getName() + '.' + var; if (findType || !last) { lastPkg = jmiUtils.getExactPackage(searchName); if (lastPkg == null) { // package doesn't exist JavaClass cls = jmiUtils.getExactClass(searchName); if (cls != null) { lastType = cls; } else { lastType = null; cont = false; } } } else { // last and searching for completion output if (last) { // get all matching fields/methods/packages String searchPkg = lastPkg.getName() + '.' + var; List res = new ArrayList(); if (isAnnotation) { res.addAll(jmiUtils.findAnnotations(lastPkg, var, false, curCls, false)); } else { res.addAll(jmiUtils.findClasses(lastPkg, var, false, curCls, !isGeneric)); // matching classes } res.addAll(jmiUtils.findPackages(searchPkg, false, false, !isGeneric)); // find matching subpackages if (isGeneric) res = filterGenericTypeArguments(res); result = new JavaResult(component, res, (isAnnotation ? "@" : "") + searchPkg + '*', item, curCls); // NOI18N } } } } break; } break; case JCExpression.ARRAY: Type arrType = resolveType(item.getParameter(0), true); cont = false; if (arrType != null) { // must be type if (item.getParameterCount() == 2) { // index in array follows Type arrIdxType = resolveType(item.getParameter(1), false); if (arrType instanceof Array && arrIdxType != null && arrIdxType instanceof PrimitiveType && ((PrimitiveType)arrIdxType).getKind().equals(PrimitiveTypeKindEnum.INT)) { lastType = ((Array)arrType).getType(); staticOnly = false; cont = true; } } else if (staticOnly) { // no index, increase array depth lastType = jmiUtils.resolveArray(arrType); if ("new".equals(item.getTokenText(0))) // NOI18N staticOnly = false; cont = true; } } break; case JCExpression.GENERIC_TYPE: lastType = resolveType(item.getParameter(0), false); if (lastType instanceof JavaClass && ((JavaClass)lastType).getTypeParameters().size() > 0) { List params = new ArrayList(item.getParameterCount() - 1); for (int i = 1; i < item.getParameterCount(); i++) params.add(resolveType(item.getParameter(i), false)); lastType = jmiUtils.resolveParameterizedType((JavaClass)lastType, params); } break; case JCExpression.INSTANCEOF: lastType = jmiUtils.resolveType("boolean"); // NOI18N break; case JCExpression.OPERATOR: if (!findType) { List res = new ArrayList(); int pos = item.getTokenOffset(0); Collection local = sup.getLocalVariableNames("", pos, openingSource); // NOI18N for (Iterator it = local.iterator(); it.hasNext();) { String name = (String) it.next(); Type t = (Type)sup.findType(name, pos); if (t != null) res.add(getJMIItemFactory().createVarResultItem(name, t, 0)); } res.addAll(findFieldsMethodsAndInnerClasses(curCls, "", openingSource, true, curCls, sup.isStaticBlock(pos), isThisContext, item, local, true)); // NOI18N res.addAll(findStaticallyImportedFeatures("", openingSource, curCls, isThisContext)); // NOI18N res.addAll(jmiUtils.findPackages("", openingSource, false, true)); // NOI18N result = new JavaResult(component, res, "*", item, endOffset, 0, curCls); // NOI18N } switch (item.getTokenID(0).getNumericID()) { case JavaTokenContext.EQ_ID: // Assignment operators case JavaTokenContext.PLUS_EQ_ID: case JavaTokenContext.MINUS_EQ_ID: case JavaTokenContext.MUL_EQ_ID: case JavaTokenContext.DIV_EQ_ID: case JavaTokenContext.AND_EQ_ID: case JavaTokenContext.OR_EQ_ID: case JavaTokenContext.XOR_EQ_ID: case JavaTokenContext.MOD_EQ_ID: case JavaTokenContext.LSHIFT_EQ_ID: case JavaTokenContext.RSSHIFT_EQ_ID: case JavaTokenContext.RUSHIFT_EQ_ID: if (item.getParameterCount() > 0) { lastType = resolveType(item.getParameter(0), false); staticOnly = false; } break; case JavaTokenContext.LT_ID: // Binary, result is boolean case JavaTokenContext.GT_ID: case JavaTokenContext.LT_EQ_ID: case JavaTokenContext.GT_EQ_ID: case JavaTokenContext.EQ_EQ_ID: case JavaTokenContext.NOT_EQ_ID: case JavaTokenContext.AND_AND_ID: // Binary, result is boolean case JavaTokenContext.OR_OR_ID: lastType = jmiUtils.resolveType("boolean"); // NOI18N break; case JavaTokenContext.LSHIFT_ID: // Always binary case JavaTokenContext.RSSHIFT_ID: case JavaTokenContext.RUSHIFT_ID: case JavaTokenContext.MUL_ID: case JavaTokenContext.DIV_ID: case JavaTokenContext.AND_ID: case JavaTokenContext.OR_ID: case JavaTokenContext.XOR_ID: case JavaTokenContext.MOD_ID: case JavaTokenContext.PLUS_ID: case JavaTokenContext.MINUS_ID: switch (item.getParameterCount()) { case 2: Type typ1 = resolveType(item.getParameter(0), false); Type typ2 = resolveType(item.getParameter(1), false); if (typ1 != null && typ2 != null && typ1 instanceof PrimitiveType && typ2 instanceof PrimitiveType ) { lastType = sup.getCommonType(typ1, typ2); } break; case 1: // get the only one parameter Type typ = resolveType(item.getParameter(0), false); if (typ != null && typ instanceof PrimitiveType) { lastType = typ; } break; } break; case JavaTokenContext.COLON_ID: switch (item.getParameterCount()) { case 2: Type typ1 = resolveType(item.getParameter(0), false); Type typ2 = resolveType(item.getParameter(1), false); if (typ1 != null && typ2 != null) { lastType = sup.getCommonType(typ1, typ2); } break; case 1: lastType = resolveType(item.getParameter(0), false); break; } break; case JavaTokenContext.QUESTION_ID: if (item.getParameterCount() >= 2) { lastType = resolveType(item.getParameter(1), false); // should be colon } break; } break; case JCExpression.UNARY_OPERATOR: if (item.getParameterCount() > 0) { lastType = resolveType(item.getParameter(0), false); } break; case JCExpression.CONVERSION: lastType = resolveType(item.getParameter(0), false); staticOnly = false; break; case JCExpression.TYPE: lastType = jmiUtils.resolveType(item.getType()); break; case JCExpression.PARENTHESIS: cont = resolveItem(item.getParameter(0), first, last); break; case JCExpression.IMPORT: // import statement isImport = true; if (item.getParameterCount() == 2) { isStaticImport = true; cont = resolveExp(item.getParameter(1)); } else if (item.getParameterCount() == 1) { cont = resolveExp(item.getParameter(0)); } break; case JCExpression.GENERIC_TYPE_OPEN: isGeneric = true; int lastIdx = item.getParameterCount() - 1; Type typ = resolveType(item.getParameter(0), false); List args = typ instanceof GenericElement ? ((GenericElement)typ).getTypeParameters() : Collections.EMPTY_LIST; if (args.size() > 0) { List tList = getTypeList(item, 1); if (item.getParameter(lastIdx).getTokenText(0).length() == 0) { lastIdx--; tList.remove(tList.size() - 1); } if (lastIdx <= args.size()) { if (lastIdx < item.getTokenCount()) { List tmp = jmiUtils.findMatchingTypes((TypeParameter) args.get(lastIdx), null, true); tmp.addAll(jmiUtils.findPackages("", openingSource, false, true)); // add matching packages String parmStr = formatTypeList(tList, true); result = new JavaResult(component, tmp, formatType(typ, true, false, false) + '<' + parmStr + '>', item, endOffset, 0, curCls); } else { TypeParameter tp = ((TypeParameter)args.get(lastIdx - 1)); typeBounds = new ArrayList(); typeBounds.add(tp.getSuperClass()); typeBounds.addAll(tp.getInterfaces()); resolveExp(item.getParameter(lastIdx)); } } } else { isGeneric = false; resolveExp(item.getParameter(1)); } break; case JCExpression.CONSTRUCTOR: // constructor can be part of a DOT expression isConstructor = true; cont = resolveExp(item.getParameter(0)); staticOnly = false; break; case JCExpression.ANNOTATION: if (item.getParameterCount() == 0) { // "@" List res = jmiUtils.findAnnotations(null, "", false, curCls, false); res.addAll(jmiUtils.findPackages("", false, false, true)); // add matching packages result = new JavaResult(component, res, "@*", item, endOffset, 0, curCls); // NOI18N } else { // "@..." isAnnotation = true; cont = resolveExp(item.getParameter(0)); } break; case JCExpression.METHOD_OPEN: methodOpen = true; // let it flow to method case JCExpression.METHOD: String mtdName = item.getTokenText(0); List genericParams = null; if (isConstructor && "<".equals(mtdName) && item.getParameterCount() > 0) { //NOI18N mtdName = item.getParameter(0).getTokenText(0); if (item.getParameterCount() > 1) genericParams = getTypeList(item, 1); } // this() invoked, offer constructors if( ("this".equals(mtdName)) && (item.getTokenCount()>0) ){ //NOI18N if (curCls != null) { isConstructor = true; mtdName = curCls.getName(); } } // super() invoked, offer constructors for super class if( ("super".equals(mtdName)) && (item.getTokenCount()>0) ){ //NOI18N JavaClass cls = curCls; if (cls != null) { cls = cls.getSuperClass(); if (cls != null) { isConstructor = true; superCall = true; mtdName = cls.getName(); } } } if (isConstructor) { // Help for the constructor Type type = null; if (first) { type = sup.getTypeFromName(mtdName, true, sup.getJavaClass(item.getTokenOffset(0))); } else { // not first if ((last)&&(lastPkg != null)) { // valid package type = jmiUtils.getExactClass(mtdName, lastPkg.getName()); } else if (lastType != null) { if(last){ // inner class type = jmiUtils.getExactClass(mtdName, lastType.getName()); }else{ type = lastType; } } } if (type instanceof JavaClass) { lastType = (type instanceof ParameterizedType && genericParams == null) ? type : jmiUtils.resolveParameterizedType((JavaClass)type, genericParams); List ctrList = jmiUtils.findConstructors(lastType, "", false, curCls); List typeList = getTypeList(item, 0); if (ctrList.size() == 0 && typeList.size() == 0) { ctrList.add(getJMIItemFactory().createDefaultConstructorResultItem((JavaClass)lastType, item)); } else { ctrList = sup.filterMethods(ctrList, typeList, methodOpen); } if (ctrList.size() > 0 && last && !findType) { String parmStr = formatTypeList(typeList, methodOpen); result = new JavaResult(component, ctrList, lastType.getName() + '(' + parmStr + ')', item, endOffset, 0, lastType instanceof JavaClass ? (JavaClass) lastType : curCls); } staticOnly = false; } else { isConstructor = false; } } if (isConstructor == false){ // Help for the method if (first) { if (curCls != null) { lastType = curCls; } } if (lastType != null) { List mtdList = jmiUtils.findMethods(lastType, mtdName, true, first, curCls, false, isThisContext, null, false, last && !findType); mtdList.addAll(jmiUtils.getStaticallyImportedMethods(mtdName, true, curCls, isThisContext)); List typeList = getTypeList(item, 0); mtdList = sup.filterMethods(mtdList, typeList, methodOpen); if (mtdList.size() > 0) { if (last && !findType) { String parmStr = formatTypeList(typeList, methodOpen); result = new JavaResult(component, mtdList, lastType.getName() + '.' + mtdName + '(' + parmStr + ')', item, endOffset, 0, lastType instanceof JavaClass ? (JavaClass) lastType : curCls); } else { lastType = ((Method)mtdList.get(0)).getType(); staticOnly = false; } } else { lastType = null; // no method found cont = false; } } else { // package.method() is invalid lastPkg = null; cont = false; } } isConstructor = false; break; } if (lastType == null && lastPkg == null) { // !!! shouldn't be necessary cont = false; } return cont; } private List filterGenericTypeArguments(List res) { if (typeBounds != null && typeBounds.size() > 0) { List tmp = new ArrayList(); for (Iterator it = res.iterator(); it.hasNext();) { Object o = it.next(); boolean toAdd = true; if (o instanceof JavaClass) { for (Iterator itt = typeBounds.iterator(); itt.hasNext();) { JavaClass bound = (JavaClass) itt.next(); if (!jmiUtils.isAssignable((JavaClass)o, bound)) { toAdd = false; break; } } } if (toAdd) { tmp.add(o); } } res = tmp; } return res; } private List getTypeList(JCExpression item, int firstChildIdx) { int parmCnt = item.getParameterCount(); ArrayList typeList = new ArrayList(); if (parmCnt > firstChildIdx) { // will try to filter by parameters for (int i = firstChildIdx; i < parmCnt; i++) { JCExpression parm = item.getParameter(i); Type typ = resolveType(parm, false); typeList.add(typ); } } return typeList; } private String formatTypeList(List typeList, boolean methodOpen) { StringBuffer sb = new StringBuffer(); if (typeList.size() > 0) { int cntM1 = typeList.size() - 1; for (int i = 0; i <= cntM1; i++) { Type t = (Type)typeList.get(i); if (t != null) { sb.append(formatType(t, false, false, false)); } else { sb.append('?'); } if (i < cntM1) { sb.append(", "); // NOI18N } } if (methodOpen) { sb.append(", *"); // NOI18N } } else { // no parameters if (methodOpen) { sb.append("*"); // NOI18N } } return sb.toString(); } private List findFieldsMethodsAndInnerClasses(Type type, String name, boolean exactMatch, boolean inspectOuterClasses, JavaClass context, boolean staticContext, boolean thisContext, JCExpression exp, Collection localVarNames, boolean simple) { List ret = new ArrayList(); for (Iterator it = jmiUtils.findFeatures(type, name, exactMatch, inspectOuterClasses, context, staticContext, thisContext, exp, true, true).iterator(); it.hasNext();) { Object f = it.next(); if (f instanceof NbJMIResultItem.MethodResultItem || f instanceof NbJMIResultItem.FieldResultItem && (localVarNames == null || !localVarNames.contains(((NbJMIResultItem.FieldResultItem)f).getFieldName())) || ((staticContext || simple) && f instanceof NbJMIResultItem.ClassResultItem)) ret.add(f); } return ret; } private List findInnerClasses(Type type, String name, boolean exactMatch, boolean inspectOuterClasses, JavaClass context, boolean thisContext, boolean createResultItems, boolean preferSources) { return jmiUtils.findInnerClasses(type, name, exactMatch, inspectOuterClasses, context, thisContext, createResultItems, preferSources); } private List findStaticallyImportedFeatures(String name, boolean exactMatch, JavaClass context, boolean isThisContext) { List ret = jmiUtils.getStaticallyImportedFields(name, exactMatch, context, isThisContext); ret.addAll(jmiUtils.getStaticallyImportedMethods(name, exactMatch, context, isThisContext)); return ret; } } public static class JavaResult extends CompletionQuery.AbstractResult { /** Expression to substitute */ private JCExpression substituteExp; /** Starting position of the text to substitute */ private int substituteOffset; /** Length of the text to substitute */ private int substituteLength; /** Component to update */ private JTextComponent component; public JavaResult(JTextComponent component, List data, String title, JCExpression substituteExp, JavaClass context) { this(component, data, title, substituteExp, substituteExp.getTokenOffset(0), substituteExp.getTokenLength(0), context); } public JavaResult(JTextComponent component, List data, String title, JCExpression substituteExp, int substituteOffset, int substituteLength, JavaClass context) { super(convertData(data, substituteExp, context), title); this.component = component; this.substituteExp = substituteExp; this.substituteOffset = substituteOffset; this.substituteLength = substituteLength; } private static List convertData(List dataList, JCExpression substituteExp, JavaClass context){ Iterator iter = dataList.iterator(); List ret = new ArrayList(); while (iter.hasNext()){ Object obj = iter.next(); if (obj instanceof CompletionQuery.ResultItem){ ret.add(obj); }else{ ret.add(getJMIItemFactory().createResultItem(obj, substituteExp, context)); } } return ret; } protected JTextComponent getComponent(){ return component; } protected int getSubstituteLength(){ return substituteLength; } protected int getSubstituteOffset(){ return substituteOffset; } protected JCExpression getSubstituteExp(){ return substituteExp; } /** Get the text that is normally filled into the text if enter is pressed. */ protected String getMainText(Object dataItem) { String text = null; if (dataItem instanceof NbJMIResultItem){ dataItem = ((NbJMIResultItem)dataItem).getAssociatedObject(); } if (dataItem instanceof NamedElement) { text = ((NamedElement)dataItem).getName(); if (dataItem instanceof JavaPackage) { text = text.substring(text.lastIndexOf('.') + 1); } } return text; } /** Get the text that is common to all the entries in the query-result */ protected String getCommonText(String prefix) { List data = getData(); int cnt = data.size(); int prefixLen = prefix.length(); String commonText = null; for (int i = 0; i < cnt; i++) { String mainText = getMainText(data.get(i)); if (mainText != null && mainText.startsWith(prefix)) { mainText = mainText.substring(prefixLen); if (commonText == null) { commonText = mainText; } // Get largest common part int minLen = Math.min(mainText.length(), commonText.length()); int commonInd; for (commonInd = 0; commonInd < minLen; commonInd++) { if (mainText.charAt(commonInd) != commonText.charAt(commonInd)) { break; } } if (commonInd != 0) { commonText = commonText.substring(0, commonInd); } else { return null; // no common text } } } return prefix + ((commonText != null) ? commonText : ""); // NOI18N } /** Update the text in response to pressing TAB key. * @return whether the text was successfully updated */ public boolean substituteCommonText(int dataIndex) { List data = getData(); if( data.size() == 0 ){ return false; } Object obj = getData().get( dataIndex ); if (obj instanceof CompletionQuery.ResultItem){ //return super.substituteCommonText(dataIndex); [PENDING] // how to get getCommonText to CompletionQuery.ResultItem ??? } BaseDocument doc = (BaseDocument)component.getDocument(); try { String prefix = doc.getText(substituteOffset, substituteLength); String commonText = getCommonText(prefix); if (commonText != null) { if(substituteExp!=null){ if( (substituteExp.getExpID()==JCExpression.METHOD_OPEN) || (substituteExp.getExpID()==JCExpression.METHOD) ) return true; } doc.atomicLock(); try { doc.remove(substituteOffset, substituteLength); doc.insertString(substituteOffset, commonText, null); } finally { doc.atomicUnlock(); } } } catch (BadLocationException e) { // no updating } return true; } /** Update the text in response to pressing ENTER. * @return whether the text was successfully updated */ public boolean substituteText(int dataIndex, boolean shift ) { Object actData = getData().get( dataIndex ); if (actData instanceof CompletionQuery.ResultItem){ return ((CompletionQuery.ResultItem)actData).substituteText( component, substituteOffset, substituteLength, shift ); } // the rest part of code is here only for backward compatibility... // it should be removed later if all data will be CompletionQuery.ResultItem BaseDocument doc = (BaseDocument)component.getDocument(); String text = null; int selectionStartOffset = -1; int selectionEndOffset = -1; Object replacement = getData().get(dataIndex); if (replacement instanceof JavaPackage) { text = ((JavaPackage)replacement).getName(); text = text.substring(text.lastIndexOf('.') + 1); } else if (replacement instanceof JavaClass) { text = ((JavaClass)replacement).getName(); } else if (replacement instanceof Field) { text = ((Field)replacement).getName(); } else if (replacement instanceof CallableFeature) { CallableFeature mtd = (CallableFeature)replacement; switch ((substituteExp != null) ? substituteExp.getExpID() : -1) { case JCExpression.METHOD: // no substitution break; case JCExpression.METHOD_OPEN: List parms = mtd.getParameters(); if (parms.size() == 0) { text = ")"; // NOI18N } else { // one or more parameters int ind = substituteExp.getParameterCount(); boolean addSpace = false; Formatter f = doc.getFormatter(); if (f instanceof ExtFormatter) { Object o = ((ExtFormatter)f).getSettingValue(JavaSettingsNames.JAVA_FORMAT_SPACE_AFTER_COMMA); if ((o instanceof Boolean) && ((Boolean)o).booleanValue()) { addSpace = true; } } try { if (addSpace && (ind == 0 || (substituteOffset > 0 && Character.isWhitespace(doc.getText(substituteOffset - 1, 1).charAt(0)))) ) { addSpace = false; } } catch (BadLocationException e) { } if (ind < parms.size()) { text = addSpace ? " " : ""; // NOI18N selectionStartOffset = text.length(); text += ((Parameter)parms.get(ind)).getName(); selectionEndOffset = text.length(); } } break; default: text = getMainText(replacement); boolean addSpace = false; Formatter f = doc.getFormatter(); if (f instanceof ExtFormatter) { Object o = ((ExtFormatter)f).getSettingValue(JavaSettingsNames.JAVA_FORMAT_SPACE_BEFORE_PARENTHESIS); if ((o instanceof Boolean) && ((Boolean)o).booleanValue()) { addSpace = true; } } if (addSpace) { text += ' '; } text += '('; parms = mtd.getParameters(); if (parms.size() > 0) { selectionStartOffset = text.length(); text += ((Parameter)parms.get(0)).getName(); selectionEndOffset = text.length(); } else { text += ")"; // NOI18N } break; } } if (text != null) { // Update the text doc.atomicLock(); try { String textToReplace = doc.getText(substituteOffset, substituteLength); if (text.equals(textToReplace)) return false; doc.remove(substituteOffset, substituteLength); doc.insertString(substituteOffset, text, null); if (selectionStartOffset >= 0) { component.select(substituteOffset + selectionStartOffset, substituteOffset + selectionEndOffset); } } catch (BadLocationException e) { // Can't update } finally { doc.atomicUnlock(); } } return true; } } protected void setJMIItemFactory(JMIItemFactory itemFactory){ jmiItemFactory = itemFactory; } public static JMIItemFactory getJMIItemFactory(){ return jmiItemFactory; } public interface JMIItemFactory{ public NbJMIResultItem.VarResultItem createVarResultItem(String varName, Type type, int modifiers); public NbJMIResultItem.PackageResultItem createPackageResultItem(JavaPackage pkg); public NbJMIResultItem.ClassResultItem createClassResultItem(JavaClass cls); public NbJMIResultItem.FieldResultItem createFieldResultItem(Field fld, JavaClass context); public NbJMIResultItem.MethodResultItem createMethodResultItem(Method mtd, JCExpression substituteExp, JavaClass context); public NbJMIResultItem.ConstructorResultItem createConstructorResultItem(Constructor ctr, JCExpression substituteExp); public NbJMIResultItem.ConstructorResultItem createDefaultConstructorResultItem(JavaClass cls, JCExpression substituteExp); public NbJMIResultItem.StringResultItem createStringResultItem(String str); public NbJMIResultItem createResultItem(Object obj, JCExpression substituteExp, JavaClass context); } public static class DefaultJMIItemFactory implements JMIItemFactory{ public NbJMIResultItem.VarResultItem createVarResultItem(String varName, Type type, int modifiers) { return new NbJMIResultItem.VarResultItem(varName, type, modifiers); } public NbJMIResultItem.PackageResultItem createPackageResultItem(JavaPackage pkg){ return new NbJMIResultItem.PackageResultItem(pkg, false); } public NbJMIResultItem.ClassResultItem createClassResultItem(JavaClass cls){ return new NbJMIResultItem.ClassResultItem(cls, false); } public NbJMIResultItem.FieldResultItem createFieldResultItem(Field fld, JavaClass context){ return new NbJMIResultItem.FieldResultItem(fld, context); } public NbJMIResultItem.MethodResultItem createMethodResultItem(Method mtd, JCExpression substituteExp, JavaClass context){ return new NbJMIResultItem.MethodResultItem(mtd, substituteExp, context); } public NbJMIResultItem.ConstructorResultItem createConstructorResultItem(Constructor ctr, JCExpression substituteExp){ return new NbJMIResultItem.ConstructorResultItem(ctr, substituteExp); } public NbJMIResultItem.ConstructorResultItem createDefaultConstructorResultItem(JavaClass cls, JCExpression substituteExp) { return new NbJMIResultItem.ConstructorResultItem(cls, substituteExp); } public NbJMIResultItem.StringResultItem createStringResultItem(String str) { return new NbJMIResultItem.StringResultItem(str); } public NbJMIResultItem createResultItem(Object obj, JCExpression substituteExp, JavaClass context){ if (obj instanceof JavaPackage) { return createPackageResultItem((JavaPackage)obj); } else if (obj instanceof JavaClass) { return createClassResultItem((JavaClass)obj); } else if (obj instanceof Field) { return createFieldResultItem((Field)obj, context); } else if (obj instanceof Method) { return createMethodResultItem((Method)obj, substituteExp, context); } else if (obj instanceof Constructor) { return createConstructorResultItem((Constructor)obj, substituteExp); } else if (obj instanceof String) { return createStringResultItem((String)obj); } return null; } } } |
... this post is sponsored by my books ... | |
#1 New Release! |
FP Best Seller |
Copyright 1998-2021 Alvin Alexander, alvinalexander.com
All Rights Reserved.
A percentage of advertising revenue from
pages under the /java/jwarehouse
URI on this website is
paid back to open source projects.