alvinalexander.com | career | drupal | java | mac | mysql | perl | scala | uml | unix  

What this is

This file is included in the DevDaily.com "Java Source Code Warehouse" project. The intent of this project is to help you "Learn Java by Example" TM.

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

 

new blog posts

 

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.