*  @param enclOp   The closest enclosing operation node of tree,
     *                  null if tree is not a subtree of an operation.
     *  @param refSuper Is access via a (qualified) C.super?
     */
    JCExpression access(Symbol sym, JCExpression tree, JCExpression enclOp, boolean refSuper) {
        // Access a free variable via its proxy, or its proxy's proxy
        while (sym.kind == VAR && sym.owner.kind == MTH &&
            sym.owner.enclClass() != currentClass) {
            // A constant is replaced by its constant value.
            Object cv = ((VarSymbol)sym).getConstValue();
            if (cv != null) {
                make.at(tree.pos);
                return makeLit(sym.type, cv);
            }
            // Otherwise replace the variable by its proxy.
            sym = proxies.lookup(proxyName(sym.name)).sym;
            Assert.check(sym != null && (sym.flags_field & FINAL) != 0);
            tree = make.at(tree.pos).Ident(sym);
        }
        JCExpression base = (tree.getTag() == JCTree.SELECT) ? ((JCFieldAccess) tree).selected : null;
        switch (sym.kind) {
        case TYP:
            if (sym.owner.kind != PCK) {
                // Convert type idents to
                // <flat name> or <package name> . <flat name>
                Name flatname = Convert.shortName(sym.flatName());
                while (base != null &&
                       TreeInfo.symbol(base) != null &&
                       TreeInfo.symbol(base).kind != PCK) {
                    base = (base.getTag() == JCTree.SELECT)
                        ? ((JCFieldAccess) base).selected
                        : null;
                }
                if (tree.getTag() == JCTree.IDENT) {
                    ((JCIdent) tree).name = flatname;
                } else if (base == null) {
                    tree = make.at(tree.pos).Ident(sym);
                    ((JCIdent) tree).name = flatname;
                } else {
                    ((JCFieldAccess) tree).selected = base;
                    ((JCFieldAccess) tree).name = flatname;
                }
            }
            break;
        case MTH: case VAR:
            if (sym.owner.kind == TYP) {

                // Access methods are required for
                //  - private members,
                //  - protected members in a superclass of an
                //    enclosing class contained in another package.
                //  - all non-private members accessed via a qualified super.
                boolean protAccess = refSuper && !needsPrivateAccess(sym)
                    || needsProtectedAccess(sym, tree);
                boolean accReq = protAccess || needsPrivateAccess(sym);

                // A base has to be supplied for
                //  - simple identifiers accessing variables in outer classes.
                boolean baseReq =
                    base == null &&
                    sym.owner != syms.predefClass &&
                    !sym.isMemberOf(currentClass, types);

                if (accReq || baseReq) {
                    make.at(tree.pos);

                    // Constants are replaced by their constant value.
                    if (sym.kind == VAR) {
                        Object cv = ((VarSymbol)sym).getConstValue();
                        if (cv != null) return makeLit(sym.type, cv);
                    }

                    // Private variables and methods are replaced by calls
                    // to their access methods.
                    if (accReq) {
                        List<JCExpression> args = List.nil();
                        if ((sym.flags() & STATIC) == 0) {
                            // Instance access methods get instance
                            // as first parameter.
                            if (base == null)
                                base = makeOwnerThis(tree.pos(), sym, true);
                            args = args.prepend(base);
                            base = null;   // so we don't duplicate code
                        }
                        Symbol access = accessSymbol(sym, tree,
                                                     enclOp, protAccess,
                                                     refSuper);
                        JCExpression receiver = make.Select(
                            base != null ? base : make.QualIdent(access.owner),
                            access);
                        return make.App(receiver, args);

                    // Other accesses to members of outer classes get a
                    // qualifier.
                    } else if (baseReq) {
                        return make.at(tree.pos).Select(
                            accessBase(tree.pos(), sym), sym).setType(tree.type);
                    }
                }
            }
        }
        return tree;
    }