private void insideMemberSelect()

in java/java.completion/src/org/netbeans/modules/java/completion/JavaCompletionTask.java [1579:1960]


    private void insideMemberSelect(Env env) throws IOException {
        int offset = env.getOffset();
        String prefix = env.getPrefix();
        TreePath path = env.getPath();
        MemberSelectTree fa = (MemberSelectTree) path.getLeaf();
        CompilationController controller = env.getController();
        CompilationUnitTree root = env.getRoot();
        SourcePositions sourcePositions = env.getSourcePositions();
        int expEndPos = (int) sourcePositions.getEndPosition(root, fa.getExpression());
        boolean afterDot = false;
        boolean afterLt = false;
        int openLtNum = 0;
        JavaTokenId lastNonWhitespaceTokenId = null;
        TokenSequence<JavaTokenId> ts = controller.getTokenHierarchy().tokenSequence(JavaTokenId.language());
        ts.move(expEndPos);
        while (ts.moveNext()) {
            if (ts.offset() >= offset) {
                break;
            }
            switch (ts.token().id()) {
                case DOUBLE_LITERAL:
                case FLOAT_LITERAL:
                case FLOAT_LITERAL_INVALID:
                case LONG_LITERAL:
                case ELLIPSIS:
                    if (ts.offset() != expEndPos || ts.token().text().charAt(0) != '.') {
                        break;
                    }
                case DOT:
                    afterDot = true;
                    break;
                case LT:
                    afterLt = true;
                    openLtNum++;
                    break;
                case GT:
                    openLtNum--;
                    break;
                case GTGT:
                    openLtNum -= 2;
                    break;
                case GTGTGT:
                    openLtNum -= 3;
                    break;
            }
            switch (ts.token().id()) {
                case WHITESPACE:
                case LINE_COMMENT:
                case BLOCK_COMMENT:
                case JAVADOC_COMMENT:
                case JAVADOC_COMMENT_LINE_RUN:
                    break;
                default:
                    lastNonWhitespaceTokenId = ts.token().id();
            }
        }
        if (!afterDot) {
            if (expEndPos <= offset) {
                insideExpression(env, new TreePath(path, fa.getExpression()));
            }
            return;
        }
        if (openLtNum > 0) {
            switch (lastNonWhitespaceTokenId) {
                case QUESTION:
                    addKeyword(env, EXTENDS_KEYWORD, SPACE, false);
                    addKeyword(env, SUPER_KEYWORD, SPACE, false);
                    break;
                case LT:
                case COMMA:
                    addClassTypes(env, null);
                    break;
                case EXTENDS:
                case SUPER:
                    addClassTypes(env, null);
                    break;
            }
        } else if (lastNonWhitespaceTokenId != JavaTokenId.STAR) {
            controller.toPhase(Phase.RESOLVED);
            if (withinModuleName(env)) {
                String fqnPrefix = fa.getExpression().toString() + '.';
                anchorOffset = (int) sourcePositions.getStartPosition(root, fa);
                addModuleNames(env, fqnPrefix, true);
                return;
            }
            TreePath parentPath = path.getParentPath();
            Tree parent = parentPath != null ? parentPath.getLeaf() : null;
            TreePath grandParentPath = parentPath != null ? parentPath.getParentPath() : null;
            Tree grandParent = grandParentPath != null ? grandParentPath.getLeaf() : null;
            ExpressionTree exp = fa.getExpression();
            TreePath expPath = new TreePath(path, exp);
            TypeMirror type = controller.getTrees().getTypeMirror(expPath);
            TypeMirror tempSwitchSelectorType;
            AddSwitchRelatedItem switchItemAdder = addSwitchItemDefault;
            AddSwitchRelatedItem tempSwitchItemAdder;
            if (type != null) {
                Element el = controller.getTrees().getElement(expPath);
                TreeUtilities tu = controller.getTreeUtilities();
                EnumSet<ElementKind> kinds;
                DeclaredType baseType = null;
                Set<TypeMirror> exs = null;
                boolean inImport = false;
                boolean insideNew = false;
                boolean srcOnly = false;
                if (TreeUtilities.CLASS_TREE_KINDS.contains(parent.getKind()) && ((ClassTree) parent).getExtendsClause() == fa) {
                    kinds = EnumSet.of(CLASS);
                    env.afterExtends();
                } else if (TreeUtilities.CLASS_TREE_KINDS.contains(parent.getKind()) && ((ClassTree) parent).getImplementsClause().contains(fa)) {
                    kinds = EnumSet.of(INTERFACE);
                } else if (parent.getKind() == Kind.PACKAGE) {
                    kinds = EnumSet.noneOf(ElementKind.class);
                    srcOnly = true;
                } else if (parent.getKind() == Tree.Kind.IMPORT) {
                    inImport = true;
                    kinds = ((ImportTree) parent).isStatic() ? EnumSet.of(CLASS, ENUM, INTERFACE, ANNOTATION_TYPE, RECORD, FIELD, METHOD, ENUM_CONSTANT, RECORD_COMPONENT) : EnumSet.of(CLASS, ANNOTATION_TYPE, ENUM, INTERFACE, RECORD);
                } else if (parent.getKind() == Tree.Kind.NEW_CLASS && ((NewClassTree) parent).getIdentifier() == fa) {
                    insideNew = true;
                    kinds = EnumSet.of(CLASS, INTERFACE, ANNOTATION_TYPE, RECORD);
                    if (grandParent.getKind() == Tree.Kind.THROW) {
                        TypeElement te = controller.getElements().getTypeElement("java.lang.Throwable"); //NOI18N
                        if (te != null) {
                            baseType = controller.getTypes().getDeclaredType(te);
                        }
                    }
                } else if (parent.getKind() == Tree.Kind.PARAMETERIZED_TYPE && ((ParameterizedTypeTree) parent).getTypeArguments().contains(fa)) {
                    kinds = EnumSet.of(CLASS, ENUM, ANNOTATION_TYPE, INTERFACE);
                } else if (parent.getKind() == Tree.Kind.ANNOTATION || parent.getKind() == Tree.Kind.TYPE_ANNOTATION) {
                    if (((AnnotationTree) parent).getAnnotationType() == fa) {
                        kinds = EnumSet.of(ANNOTATION_TYPE);
                    } else {
                        Iterator<? extends ExpressionTree> it = ((AnnotationTree) parent).getArguments().iterator();
                        if (it.hasNext()) {
                            ExpressionTree et = it.next();
                            if (et == fa || (et.getKind() == Tree.Kind.ASSIGNMENT && ((AssignmentTree) et).getExpression() == fa)) {
                                if (type.getKind() == TypeKind.ERROR && el.getKind().isClass()) {
                                    el = controller.getElements().getPackageElement(((TypeElement) el).getQualifiedName());
                                }
                                if (el instanceof PackageElement) {
                                    addPackageContent(env, (PackageElement) el, EnumSet.of(CLASS, ENUM, ANNOTATION_TYPE, INTERFACE), null, false, false);
                                } else if (type.getKind() == TypeKind.DECLARED) {
                                    addMemberConstantsAndTypes(env, (DeclaredType) type, el);
                                }
                                return;
                            }
                        }
                        kinds = EnumSet.of(CLASS, ENUM, ANNOTATION_TYPE, INTERFACE, RECORD, FIELD, METHOD, ENUM_CONSTANT, RECORD_COMPONENT);
                    }
                } else if (parent.getKind() == Tree.Kind.ASSIGNMENT && ((AssignmentTree) parent).getExpression() == fa && grandParent != null && grandParent.getKind() == Tree.Kind.ANNOTATION) {
                    if (type.getKind() == TypeKind.ERROR && el.getKind().isClass()) {
                        el = controller.getElements().getPackageElement(((TypeElement) el).getQualifiedName());
                    }
                    if (el instanceof PackageElement) {
                        addPackageContent(env, (PackageElement) el, EnumSet.of(CLASS, ENUM, ANNOTATION_TYPE, INTERFACE, RECORD), null, false, false);
                    } else if (type.getKind() == TypeKind.DECLARED) {
                        addMemberConstantsAndTypes(env, (DeclaredType) type, el);
                    }
                    return;
                } else if (parent.getKind() == Tree.Kind.VARIABLE && ((VariableTree) parent).getType() == fa) {
                    if (grandParent.getKind() == Tree.Kind.CATCH) {
                        kinds = EnumSet.of(CLASS, INTERFACE);
                        if (!options.contains(Options.ALL_COMPLETION)) {
                            exs = controller.getTreeUtilities().getUncaughtExceptions(grandParentPath.getParentPath());
                        }
                        TypeElement te = controller.getElements().getTypeElement("java.lang.Throwable"); //NOI18N
                        if (te != null) {
                            baseType = controller.getTypes().getDeclaredType(te);
                        }
                    } else {
                        kinds = EnumSet.of(CLASS, ENUM, ANNOTATION_TYPE, INTERFACE, RECORD);
                    }
                } else if (parent.getKind() == Tree.Kind.METHOD && ((MethodTree) parent).getThrows().contains(fa)) {
                    Types types = controller.getTypes();
                    if (!options.contains(Options.ALL_COMPLETION) && ((MethodTree) parent).getBody() != null) {
                        controller.toPhase(Phase.RESOLVED);
                        exs = controller.getTreeUtilities().getUncaughtExceptions(new TreePath(path, ((MethodTree) parent).getBody()));
                        Trees trees = controller.getTrees();
                        for (ExpressionTree thr : ((MethodTree) parent).getThrows()) {
                            if (sourcePositions.getEndPosition(root, thr) >= offset) {
                                break;
                            }
                            TypeMirror t = trees.getTypeMirror(new TreePath(path, thr));
                            for (Iterator<TypeMirror> it = exs.iterator(); it.hasNext();) {
                                if (types.isSubtype(it.next(), t)) {
                                    it.remove();
                                }
                            }
                        }
                    }
                    kinds = EnumSet.of(CLASS, INTERFACE);
                    TypeElement te = controller.getElements().getTypeElement("java.lang.Throwable"); //NOI18N
                    if (te != null) {
                        baseType = controller.getTypes().getDeclaredType(te);
                    }
                } else if (parent.getKind() == Tree.Kind.METHOD && ((MethodTree) parent).getDefaultValue() == fa) {
                    if (type.getKind() == TypeKind.ERROR && el.getKind().isClass()) {
                        el = controller.getElements().getPackageElement(((TypeElement) el).getQualifiedName());
                    }
                    if (el instanceof PackageElement) {
                        addPackageContent(env, (PackageElement) el, EnumSet.of(CLASS, ENUM, ANNOTATION_TYPE, INTERFACE, RECORD), null, false, false);
                    } else if (type.getKind() == TypeKind.DECLARED) {
                        addMemberConstantsAndTypes(env, (DeclaredType) type, el);
                    }
                    return;
                } else if (parent.getKind() == Tree.Kind.TYPE_PARAMETER) {
                    TypeParameterTree tpt = (TypeParameterTree) parent;
                    Trees trees = controller.getTrees();
                    boolean first = true;
                    for (Tree bound : tpt.getBounds()) {
                        int pos = (int) sourcePositions.getEndPosition(root, bound);
                        if (offset <= pos) {
                            break;
                        }
                        first = false;
                        env.addToExcludes(trees.getElement(new TreePath(parentPath, bound)));
                    }
                    kinds = first ? EnumSet.of(CLASS, ENUM, ANNOTATION_TYPE, INTERFACE) : EnumSet.of(ANNOTATION_TYPE, INTERFACE);
                } else if (parent.getKind() == Tree.Kind.AND) {
                    TypeMirror tm = controller.getTrees().getTypeMirror(new TreePath(path, ((BinaryTree) parent).getLeftOperand()));
                    if (tm != null && tm.getKind() == TypeKind.DECLARED) {
                        env.addToExcludes(((DeclaredType) tm).asElement());
                        kinds = EnumSet.of(INTERFACE, ANNOTATION_TYPE);
                    } else if (tm != null && tm.getKind() == TypeKind.INTERSECTION) {
                        for (TypeMirror bound : ((IntersectionType) tm).getBounds()) {
                            if (bound.getKind() == TypeKind.DECLARED) {
                                env.addToExcludes(((DeclaredType) bound).asElement());
                            }
                        }
                        kinds = EnumSet.of(INTERFACE, ANNOTATION_TYPE);
                    } else {
                        kinds = EnumSet.of(CLASS, ENUM, ANNOTATION_TYPE, INTERFACE, RECORD, FIELD, METHOD, ENUM_CONSTANT, RECORD_COMPONENT);
                    }
                } else if (afterLt) {
                    kinds = EnumSet.of(METHOD);
                } else if (parent.getKind() == Tree.Kind.ENHANCED_FOR_LOOP && ((EnhancedForLoopTree) parent).getExpression() == fa) {
                    env.insideForEachExpression();
                    kinds = EnumSet.of(CLASS, ENUM, ANNOTATION_TYPE, INTERFACE, RECORD, FIELD, METHOD, ENUM_CONSTANT, RECORD_COMPONENT);
                } else if (tu.getPathElementOfKind(Tree.Kind.EXPORTS, path) != null) {
                    kinds = EnumSet.noneOf(ElementKind.class);
                    srcOnly = true;
                } else if (tu.getPathElementOfKind(Tree.Kind.PROVIDES, path) != null) {                    
                    kinds = withinProvidesService(env) ? EnumSet.of(ANNOTATION_TYPE, CLASS, INTERFACE) : EnumSet.of(CLASS);
                } else if (tu.getPathElementOfKind(Tree.Kind.USES, path) != null) {
                    kinds = EnumSet.of(ANNOTATION_TYPE, CLASS, INTERFACE);
                } else if (parent.getKind() == Kind.CONSTANT_CASE_LABEL &&
                           grandParent != null &&
                           grandParent.getKind() == Kind.CASE &&
                           (tempSwitchSelectorType = getSwitchSelectorType(env, grandParentPath.getParentPath())) != null &&
                           tempSwitchSelectorType.getKind() == TypeKind.DECLARED &&
                           (tempSwitchItemAdder = itemAdderForSwitchOrNull(env, grandParentPath.getParentPath())) != null) {
                    kinds = EnumSet.of(CLASS, ENUM, ANNOTATION_TYPE, INTERFACE, RECORD, ENUM_CONSTANT);
                    baseType = (DeclaredType) tempSwitchSelectorType;
                    switchItemAdder = tempSwitchItemAdder;
                } else {
                    kinds = EnumSet.of(CLASS, ENUM, ANNOTATION_TYPE, INTERFACE, RECORD, FIELD, METHOD, ENUM_CONSTANT, RECORD_COMPONENT);
                }
                switch (type.getKind()) {
                    case TYPEVAR:
                        while (type != null && type.getKind() == TypeKind.TYPEVAR) {
                            type = ((TypeVariable) type).getUpperBound();
                        }
                        if (type == null) {
                            return;
                        }
                        type = controller.getTypes().capture(type);
                    case ARRAY:
                    case DECLARED:
                    case UNION:
                    case BOOLEAN:
                    case BYTE:
                    case CHAR:
                    case DOUBLE:
                    case FLOAT:
                    case INT:
                    case LONG:
                    case SHORT:
                    case VOID:
                        boolean b = exp.getKind() == Tree.Kind.PARENTHESIZED || exp.getKind() == Tree.Kind.TYPE_CAST;
                        while (b) {
                            if (exp.getKind() == Tree.Kind.PARENTHESIZED) {
                                exp = ((ParenthesizedTree) exp).getExpression();
                                expPath = new TreePath(expPath, exp);
                            } else if (exp.getKind() == Tree.Kind.TYPE_CAST) {
                                exp = ((TypeCastTree) exp).getExpression();
                                expPath = new TreePath(expPath, exp);
                            } else {
                                b = false;
                            }
                        }
                        el = controller.getTrees().getElement(expPath);
                        if (el != null && (el.getKind().isClass() || el.getKind().isInterface())) {
                            if (parent.getKind() == Tree.Kind.NEW_CLASS && ((NewClassTree) parent).getIdentifier() == fa && prefix != null) {
                                String typeName = controller.getElementUtilities().getElementName(el, true) + "." + prefix; //NOI18N
                                TypeMirror tm = controller.getTreeUtilities().parseType(typeName, env.getScope().getEnclosingClass());
                                if (tm != null && tm.getKind() == TypeKind.DECLARED) {
                                    addMembers(env, tm, ((DeclaredType) tm).asElement(), EnumSet.of(CONSTRUCTOR), null, inImport, insideNew, false, false, switchItemAdder);
                                }
                            }
                        }
                        if (exs != null && !exs.isEmpty()) {
                            Elements elements = controller.getElements();
                            for (TypeMirror ex : exs) {
                                if (ex.getKind() == TypeKind.DECLARED) {
                                    Element e = ((DeclaredType) ex).asElement();
                                    if (e.getEnclosingElement() == el && startsWith(env, e.getSimpleName().toString()) && (Utilities.isShowDeprecatedMembers() || !elements.isDeprecated(e)) && !Utilities.isExcluded(((TypeElement)e).getQualifiedName())) {
                                        env.addToExcludes(e);
                                        results.add(itemFactory.createTypeItem(env.getController(), (TypeElement) e, (DeclaredType) ex, anchorOffset, null, elements.isDeprecated(e), insideNew, insideNew || env.isInsideClass(), true, true, false));
                                    }
                                }
                            }
                        } else {
                            if (el == null) {
                                if (exp.getKind() == Tree.Kind.ARRAY_TYPE) {
                                    TypeMirror tm = type;
                                    while (tm.getKind() == TypeKind.ARRAY) {
                                        tm = ((ArrayType) tm).getComponentType();
                                    }
                                    if (tm.getKind().isPrimitive()) {
                                        el = controller.getTypes().boxedClass((PrimitiveType) tm);
                                    } else if (tm.getKind() == TypeKind.DECLARED) {
                                        el = ((DeclaredType) tm).asElement();
                                    }
                                } else if (exp.getKind() == Tree.Kind.PRIMITIVE_TYPE) {
                                    if (type.getKind().isPrimitive()) {
                                        el = controller.getTypes().boxedClass((PrimitiveType) type);
                                    } else if (type.getKind() == TypeKind.VOID) {
                                        el = controller.getElements().getTypeElement("java.lang.Void"); //NOI18N
                                    }
                                }
                            }
                            addMembers(env, type, el, kinds, baseType, inImport, insideNew, false, false, switchItemAdder);
                        }
                        break;
                    default:
                        el = controller.getTrees().getElement(expPath);
                        if (type.getKind() == TypeKind.ERROR && el != null && el.getKind().isClass()) {
                            el = controller.getElements().getPackageElement(((TypeElement) el).getQualifiedName());
                        }
                        if (el != null && el.getKind() == PACKAGE) {
                            if (parent.getKind() == Tree.Kind.NEW_CLASS && ((NewClassTree) parent).getIdentifier() == fa && prefix != null) {
                                String typeName = controller.getElementUtilities().getElementName(el, true) + "." + prefix; //NOI18N
                                TypeMirror tm = controller.getTreeUtilities().parseType(typeName, env.getScope().getEnclosingClass());
                                if (tm != null && tm.getKind() == TypeKind.DECLARED) {
                                    addMembers(env, tm, ((DeclaredType) tm).asElement(), EnumSet.of(CONSTRUCTOR), null, inImport, insideNew, false, false, switchItemAdder);
                                }
                            }
                            if (exs != null && !exs.isEmpty()) {
                                Elements elements = controller.getElements();
                                for (TypeMirror ex : exs) {
                                    if (ex.getKind() == TypeKind.DECLARED) {
                                        Element e = ((DeclaredType) ex).asElement();
                                        if (e.getEnclosingElement() == el && startsWith(env, e.getSimpleName().toString()) && (Utilities.isShowDeprecatedMembers() || !elements.isDeprecated(e)) && !Utilities.isExcluded(((TypeElement)e).getQualifiedName())) {
                                            env.addToExcludes(e);
                                            switchItemAdder.addTypeItem(env.getController(), (TypeElement) e, (DeclaredType) ex, anchorOffset, env.getReferencesCount(), elements.isDeprecated(e), false, env.isInsideClass(), true, true, false);
                                        }
                                    }
                                }
                            }
                            addPackageContent(env, (PackageElement) el, kinds, baseType, insideNew, srcOnly, switchItemAdder);
                            if (results.isEmpty() && ((PackageElement) el).getQualifiedName() == el.getSimpleName()) {
                                // no package content? Check for unimported class
                                ClassIndex ci = controller.getClasspathInfo().getClassIndex();
                                if (el.getEnclosedElements().isEmpty() && ci.getPackageNames(el.getSimpleName() + ".", true, EnumSet.allOf(ClassIndex.SearchScope.class)).isEmpty()) {
                                    Trees trees = controller.getTrees();
                                    Scope scope = env.getScope();
                                    for (ElementHandle<TypeElement> teHandle : ci.getDeclaredTypes(el.getSimpleName().toString(), ClassIndex.NameKind.SIMPLE_NAME, EnumSet.allOf(ClassIndex.SearchScope.class))) {
                                        TypeElement te = teHandle.resolve(controller);
                                        if (te != null && trees.isAccessible(scope, te)) {
                                            addMembers(env, te.asType(), te, kinds, baseType, inImport, insideNew, true, false, switchItemAdder);
                                        }
                                    }
                                }
                            }
                        }
                }
            } else if (parent.getKind() == Tree.Kind.COMPILATION_UNIT && ((CompilationUnitTree) parent).getPackageName() == fa) {
                PackageElement pe = controller.getElements().getPackageElement(fullName(exp));
                if (pe != null) {
                    addPackageContent(env, pe, EnumSet.of(ElementKind.PACKAGE), null, false, true);
                }
            }
        }
    }