Lower.java revision 4011:28a6e8d3ccc7
1/*
2 * Copyright (c) 1999, 2017, Oracle and/or its affiliates. All rights reserved.
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * This code is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License version 2 only, as
7 * published by the Free Software Foundation.  Oracle designates this
8 * particular file as subject to the "Classpath" exception as provided
9 * by Oracle in the LICENSE file that accompanied this code.
10 *
11 * This code is distributed in the hope that it will be useful, but WITHOUT
12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
14 * version 2 for more details (a copy is included in the LICENSE file that
15 * accompanied this code).
16 *
17 * You should have received a copy of the GNU General Public License version
18 * 2 along with this work; if not, write to the Free Software Foundation,
19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20 *
21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22 * or visit www.oracle.com if you need additional information or have any
23 * questions.
24 */
25
26package com.sun.tools.javac.comp;
27
28import java.util.*;
29
30import com.sun.tools.javac.code.*;
31import com.sun.tools.javac.code.Kinds.KindSelector;
32import com.sun.tools.javac.code.Scope.WriteableScope;
33import com.sun.tools.javac.jvm.*;
34import com.sun.tools.javac.main.Option.PkgInfo;
35import com.sun.tools.javac.tree.*;
36import com.sun.tools.javac.util.*;
37import com.sun.tools.javac.util.JCDiagnostic.DiagnosticPosition;
38import com.sun.tools.javac.util.List;
39
40import com.sun.tools.javac.code.Symbol.*;
41import com.sun.tools.javac.code.Symbol.OperatorSymbol.AccessCode;
42import com.sun.tools.javac.tree.JCTree.*;
43import com.sun.tools.javac.code.Type.*;
44
45import com.sun.tools.javac.jvm.Target;
46import com.sun.tools.javac.tree.EndPosTable;
47
48import static com.sun.tools.javac.code.Flags.*;
49import static com.sun.tools.javac.code.Flags.BLOCK;
50import static com.sun.tools.javac.code.Scope.LookupKind.NON_RECURSIVE;
51import static com.sun.tools.javac.code.TypeTag.*;
52import static com.sun.tools.javac.code.Kinds.Kind.*;
53import static com.sun.tools.javac.code.Symbol.OperatorSymbol.AccessCode.DEREF;
54import static com.sun.tools.javac.jvm.ByteCodes.*;
55import static com.sun.tools.javac.tree.JCTree.JCOperatorExpression.OperandPos.LEFT;
56import static com.sun.tools.javac.tree.JCTree.Tag.*;
57
58/** This pass translates away some syntactic sugar: inner classes,
59 *  class literals, assertions, foreach loops, etc.
60 *
61 *  <p><b>This is NOT part of any supported API.
62 *  If you write code that depends on this, you do so at your own risk.
63 *  This code and its internal interfaces are subject to change or
64 *  deletion without notice.</b>
65 */
66public class Lower extends TreeTranslator {
67    protected static final Context.Key<Lower> lowerKey = new Context.Key<>();
68
69    public static Lower instance(Context context) {
70        Lower instance = context.get(lowerKey);
71        if (instance == null)
72            instance = new Lower(context);
73        return instance;
74    }
75
76    private final Names names;
77    private final Log log;
78    private final Symtab syms;
79    private final Resolve rs;
80    private final Operators operators;
81    private final Check chk;
82    private final Attr attr;
83    private TreeMaker make;
84    private DiagnosticPosition make_pos;
85    private final ClassWriter writer;
86    private final ConstFold cfolder;
87    private final Target target;
88    private final Source source;
89    private final TypeEnvs typeEnvs;
90    private final Name dollarAssertionsDisabled;
91    private final Name classDollar;
92    private final Name dollarCloseResource;
93    private final Types types;
94    private final boolean debugLower;
95    private final PkgInfo pkginfoOpt;
96
97    protected Lower(Context context) {
98        context.put(lowerKey, this);
99        names = Names.instance(context);
100        log = Log.instance(context);
101        syms = Symtab.instance(context);
102        rs = Resolve.instance(context);
103        operators = Operators.instance(context);
104        chk = Check.instance(context);
105        attr = Attr.instance(context);
106        make = TreeMaker.instance(context);
107        writer = ClassWriter.instance(context);
108        cfolder = ConstFold.instance(context);
109        target = Target.instance(context);
110        source = Source.instance(context);
111        typeEnvs = TypeEnvs.instance(context);
112        dollarAssertionsDisabled = names.
113            fromString(target.syntheticNameChar() + "assertionsDisabled");
114        classDollar = names.
115            fromString("class" + target.syntheticNameChar());
116        dollarCloseResource = names.
117            fromString(target.syntheticNameChar() + "closeResource");
118
119        types = Types.instance(context);
120        Options options = Options.instance(context);
121        debugLower = options.isSet("debuglower");
122        pkginfoOpt = PkgInfo.get(options);
123    }
124
125    /** The currently enclosing class.
126     */
127    ClassSymbol currentClass;
128
129    /** A queue of all translated classes.
130     */
131    ListBuffer<JCTree> translated;
132
133    /** Environment for symbol lookup, set by translateTopLevelClass.
134     */
135    Env<AttrContext> attrEnv;
136
137    /** A hash table mapping syntax trees to their ending source positions.
138     */
139    EndPosTable endPosTable;
140
141/**************************************************************************
142 * Global mappings
143 *************************************************************************/
144
145    /** A hash table mapping local classes to their definitions.
146     */
147    Map<ClassSymbol, JCClassDecl> classdefs;
148
149    /** A hash table mapping local classes to a list of pruned trees.
150     */
151    public Map<ClassSymbol, List<JCTree>> prunedTree = new WeakHashMap<>();
152
153    /** A hash table mapping virtual accessed symbols in outer subclasses
154     *  to the actually referred symbol in superclasses.
155     */
156    Map<Symbol,Symbol> actualSymbols;
157
158    /** The current method definition.
159     */
160    JCMethodDecl currentMethodDef;
161
162    /** The current method symbol.
163     */
164    MethodSymbol currentMethodSym;
165
166    /** The currently enclosing outermost class definition.
167     */
168    JCClassDecl outermostClassDef;
169
170    /** The currently enclosing outermost member definition.
171     */
172    JCTree outermostMemberDef;
173
174    /** A map from local variable symbols to their translation (as per LambdaToMethod).
175     * This is required when a capturing local class is created from a lambda (in which
176     * case the captured symbols should be replaced with the translated lambda symbols).
177     */
178    Map<Symbol, Symbol> lambdaTranslationMap = null;
179
180    /** A navigator class for assembling a mapping from local class symbols
181     *  to class definition trees.
182     *  There is only one case; all other cases simply traverse down the tree.
183     */
184    class ClassMap extends TreeScanner {
185
186        /** All encountered class defs are entered into classdefs table.
187         */
188        public void visitClassDef(JCClassDecl tree) {
189            classdefs.put(tree.sym, tree);
190            super.visitClassDef(tree);
191        }
192    }
193    ClassMap classMap = new ClassMap();
194
195    /** Map a class symbol to its definition.
196     *  @param c    The class symbol of which we want to determine the definition.
197     */
198    JCClassDecl classDef(ClassSymbol c) {
199        // First lookup the class in the classdefs table.
200        JCClassDecl def = classdefs.get(c);
201        if (def == null && outermostMemberDef != null) {
202            // If this fails, traverse outermost member definition, entering all
203            // local classes into classdefs, and try again.
204            classMap.scan(outermostMemberDef);
205            def = classdefs.get(c);
206        }
207        if (def == null) {
208            // If this fails, traverse outermost class definition, entering all
209            // local classes into classdefs, and try again.
210            classMap.scan(outermostClassDef);
211            def = classdefs.get(c);
212        }
213        return def;
214    }
215
216    /** A hash table mapping class symbols to lists of free variables.
217     *  accessed by them. Only free variables of the method immediately containing
218     *  a class are associated with that class.
219     */
220    Map<ClassSymbol,List<VarSymbol>> freevarCache;
221
222    /** A navigator class for collecting the free variables accessed
223     *  from a local class. There is only one case; all other cases simply
224     *  traverse down the tree. This class doesn't deal with the specific
225     *  of Lower - it's an abstract visitor that is meant to be reused in
226     *  order to share the local variable capture logic.
227     */
228    abstract class BasicFreeVarCollector extends TreeScanner {
229
230        /** Add all free variables of class c to fvs list
231         *  unless they are already there.
232         */
233        abstract void addFreeVars(ClassSymbol c);
234
235        /** If tree refers to a variable in owner of local class, add it to
236         *  free variables list.
237         */
238        public void visitIdent(JCIdent tree) {
239            visitSymbol(tree.sym);
240        }
241        // where
242        abstract void visitSymbol(Symbol _sym);
243
244        /** If tree refers to a class instance creation expression
245         *  add all free variables of the freshly created class.
246         */
247        public void visitNewClass(JCNewClass tree) {
248            ClassSymbol c = (ClassSymbol)tree.constructor.owner;
249            addFreeVars(c);
250            super.visitNewClass(tree);
251        }
252
253        /** If tree refers to a superclass constructor call,
254         *  add all free variables of the superclass.
255         */
256        public void visitApply(JCMethodInvocation tree) {
257            if (TreeInfo.name(tree.meth) == names._super) {
258                addFreeVars((ClassSymbol) TreeInfo.symbol(tree.meth).owner);
259            }
260            super.visitApply(tree);
261        }
262    }
263
264    /**
265     * Lower-specific subclass of {@code BasicFreeVarCollector}.
266     */
267    class FreeVarCollector extends BasicFreeVarCollector {
268
269        /** The owner of the local class.
270         */
271        Symbol owner;
272
273        /** The local class.
274         */
275        ClassSymbol clazz;
276
277        /** The list of owner's variables accessed from within the local class,
278         *  without any duplicates.
279         */
280        List<VarSymbol> fvs;
281
282        FreeVarCollector(ClassSymbol clazz) {
283            this.clazz = clazz;
284            this.owner = clazz.owner;
285            this.fvs = List.nil();
286        }
287
288        /** Add free variable to fvs list unless it is already there.
289         */
290        private void addFreeVar(VarSymbol v) {
291            for (List<VarSymbol> l = fvs; l.nonEmpty(); l = l.tail)
292                if (l.head == v) return;
293            fvs = fvs.prepend(v);
294        }
295
296        @Override
297        void addFreeVars(ClassSymbol c) {
298            List<VarSymbol> fvs = freevarCache.get(c);
299            if (fvs != null) {
300                for (List<VarSymbol> l = fvs; l.nonEmpty(); l = l.tail) {
301                    addFreeVar(l.head);
302                }
303            }
304        }
305
306        @Override
307        void visitSymbol(Symbol _sym) {
308            Symbol sym = _sym;
309            if (sym.kind == VAR || sym.kind == MTH) {
310                while (sym != null && sym.owner != owner)
311                    sym = proxies.findFirst(proxyName(sym.name));
312                if (sym != null && sym.owner == owner) {
313                    VarSymbol v = (VarSymbol)sym;
314                    if (v.getConstValue() == null) {
315                        addFreeVar(v);
316                    }
317                } else {
318                    if (outerThisStack.head != null &&
319                        outerThisStack.head != _sym)
320                        visitSymbol(outerThisStack.head);
321                }
322            }
323        }
324
325        /** If tree refers to a class instance creation expression
326         *  add all free variables of the freshly created class.
327         */
328        public void visitNewClass(JCNewClass tree) {
329            ClassSymbol c = (ClassSymbol)tree.constructor.owner;
330            if (tree.encl == null &&
331                c.hasOuterInstance() &&
332                outerThisStack.head != null)
333                visitSymbol(outerThisStack.head);
334            super.visitNewClass(tree);
335        }
336
337        /** If tree refers to a qualified this or super expression
338         *  for anything but the current class, add the outer this
339         *  stack as a free variable.
340         */
341        public void visitSelect(JCFieldAccess tree) {
342            if ((tree.name == names._this || tree.name == names._super) &&
343                tree.selected.type.tsym != clazz &&
344                outerThisStack.head != null)
345                visitSymbol(outerThisStack.head);
346            super.visitSelect(tree);
347        }
348
349        /** If tree refers to a superclass constructor call,
350         *  add all free variables of the superclass.
351         */
352        public void visitApply(JCMethodInvocation tree) {
353            if (TreeInfo.name(tree.meth) == names._super) {
354                Symbol constructor = TreeInfo.symbol(tree.meth);
355                ClassSymbol c = (ClassSymbol)constructor.owner;
356                if (c.hasOuterInstance() &&
357                    !tree.meth.hasTag(SELECT) &&
358                    outerThisStack.head != null)
359                    visitSymbol(outerThisStack.head);
360            }
361            super.visitApply(tree);
362        }
363    }
364
365    ClassSymbol ownerToCopyFreeVarsFrom(ClassSymbol c) {
366        if (!c.isLocal()) {
367            return null;
368        }
369        Symbol currentOwner = c.owner;
370        while (currentOwner.owner.kind.matches(KindSelector.TYP) && currentOwner.isLocal()) {
371            currentOwner = currentOwner.owner;
372        }
373        if (currentOwner.owner.kind.matches(KindSelector.VAL_MTH) && c.isSubClass(currentOwner, types)) {
374            return (ClassSymbol)currentOwner;
375        }
376        return null;
377    }
378
379    /** Return the variables accessed from within a local class, which
380     *  are declared in the local class' owner.
381     *  (in reverse order of first access).
382     */
383    List<VarSymbol> freevars(ClassSymbol c)  {
384        List<VarSymbol> fvs = freevarCache.get(c);
385        if (fvs != null) {
386            return fvs;
387        }
388        if (c.owner.kind.matches(KindSelector.VAL_MTH)) {
389            FreeVarCollector collector = new FreeVarCollector(c);
390            collector.scan(classDef(c));
391            fvs = collector.fvs;
392            freevarCache.put(c, fvs);
393            return fvs;
394        } else {
395            ClassSymbol owner = ownerToCopyFreeVarsFrom(c);
396            if (owner != null) {
397                fvs = freevarCache.get(owner);
398                freevarCache.put(c, fvs);
399                return fvs;
400            } else {
401                return List.nil();
402            }
403        }
404    }
405
406    Map<TypeSymbol,EnumMapping> enumSwitchMap = new LinkedHashMap<>();
407
408    EnumMapping mapForEnum(DiagnosticPosition pos, TypeSymbol enumClass) {
409        EnumMapping map = enumSwitchMap.get(enumClass);
410        if (map == null)
411            enumSwitchMap.put(enumClass, map = new EnumMapping(pos, enumClass));
412        return map;
413    }
414
415    /** This map gives a translation table to be used for enum
416     *  switches.
417     *
418     *  <p>For each enum that appears as the type of a switch
419     *  expression, we maintain an EnumMapping to assist in the
420     *  translation, as exemplified by the following example:
421     *
422     *  <p>we translate
423     *  <pre>
424     *          switch(colorExpression) {
425     *          case red: stmt1;
426     *          case green: stmt2;
427     *          }
428     *  </pre>
429     *  into
430     *  <pre>
431     *          switch(Outer$0.$EnumMap$Color[colorExpression.ordinal()]) {
432     *          case 1: stmt1;
433     *          case 2: stmt2
434     *          }
435     *  </pre>
436     *  with the auxiliary table initialized as follows:
437     *  <pre>
438     *          class Outer$0 {
439     *              synthetic final int[] $EnumMap$Color = new int[Color.values().length];
440     *              static {
441     *                  try { $EnumMap$Color[red.ordinal()] = 1; } catch (NoSuchFieldError ex) {}
442     *                  try { $EnumMap$Color[green.ordinal()] = 2; } catch (NoSuchFieldError ex) {}
443     *              }
444     *          }
445     *  </pre>
446     *  class EnumMapping provides mapping data and support methods for this translation.
447     */
448    class EnumMapping {
449        EnumMapping(DiagnosticPosition pos, TypeSymbol forEnum) {
450            this.forEnum = forEnum;
451            this.values = new LinkedHashMap<>();
452            this.pos = pos;
453            Name varName = names
454                .fromString(target.syntheticNameChar() +
455                            "SwitchMap" +
456                            target.syntheticNameChar() +
457                            writer.xClassName(forEnum.type).toString()
458                            .replace('/', '.')
459                            .replace('.', target.syntheticNameChar()));
460            ClassSymbol outerCacheClass = outerCacheClass();
461            this.mapVar = new VarSymbol(STATIC | SYNTHETIC | FINAL,
462                                        varName,
463                                        new ArrayType(syms.intType, syms.arrayClass),
464                                        outerCacheClass);
465            enterSynthetic(pos, mapVar, outerCacheClass.members());
466        }
467
468        DiagnosticPosition pos = null;
469
470        // the next value to use
471        int next = 1; // 0 (unused map elements) go to the default label
472
473        // the enum for which this is a map
474        final TypeSymbol forEnum;
475
476        // the field containing the map
477        final VarSymbol mapVar;
478
479        // the mapped values
480        final Map<VarSymbol,Integer> values;
481
482        JCLiteral forConstant(VarSymbol v) {
483            Integer result = values.get(v);
484            if (result == null)
485                values.put(v, result = next++);
486            return make.Literal(result);
487        }
488
489        // generate the field initializer for the map
490        void translate() {
491            make.at(pos.getStartPosition());
492            JCClassDecl owner = classDef((ClassSymbol)mapVar.owner);
493
494            // synthetic static final int[] $SwitchMap$Color = new int[Color.values().length];
495            MethodSymbol valuesMethod = lookupMethod(pos,
496                                                     names.values,
497                                                     forEnum.type,
498                                                     List.nil());
499            JCExpression size = make // Color.values().length
500                .Select(make.App(make.QualIdent(valuesMethod)),
501                        syms.lengthVar);
502            JCExpression mapVarInit = make
503                .NewArray(make.Type(syms.intType), List.of(size), null)
504                .setType(new ArrayType(syms.intType, syms.arrayClass));
505
506            // try { $SwitchMap$Color[red.ordinal()] = 1; } catch (java.lang.NoSuchFieldError ex) {}
507            ListBuffer<JCStatement> stmts = new ListBuffer<>();
508            Symbol ordinalMethod = lookupMethod(pos,
509                                                names.ordinal,
510                                                forEnum.type,
511                                                List.nil());
512            List<JCCatch> catcher = List.<JCCatch>nil()
513                .prepend(make.Catch(make.VarDef(new VarSymbol(PARAMETER, names.ex,
514                                                              syms.noSuchFieldErrorType,
515                                                              syms.noSymbol),
516                                                null),
517                                    make.Block(0, List.nil())));
518            for (Map.Entry<VarSymbol,Integer> e : values.entrySet()) {
519                VarSymbol enumerator = e.getKey();
520                Integer mappedValue = e.getValue();
521                JCExpression assign = make
522                    .Assign(make.Indexed(mapVar,
523                                         make.App(make.Select(make.QualIdent(enumerator),
524                                                              ordinalMethod))),
525                            make.Literal(mappedValue))
526                    .setType(syms.intType);
527                JCStatement exec = make.Exec(assign);
528                JCStatement _try = make.Try(make.Block(0, List.of(exec)), catcher, null);
529                stmts.append(_try);
530            }
531
532            owner.defs = owner.defs
533                .prepend(make.Block(STATIC, stmts.toList()))
534                .prepend(make.VarDef(mapVar, mapVarInit));
535        }
536    }
537
538
539/**************************************************************************
540 * Tree building blocks
541 *************************************************************************/
542
543    /** Equivalent to make.at(pos.getStartPosition()) with side effect of caching
544     *  pos as make_pos, for use in diagnostics.
545     **/
546    TreeMaker make_at(DiagnosticPosition pos) {
547        make_pos = pos;
548        return make.at(pos);
549    }
550
551    /** Make an attributed tree representing a literal. This will be an
552     *  Ident node in the case of boolean literals, a Literal node in all
553     *  other cases.
554     *  @param type       The literal's type.
555     *  @param value      The literal's value.
556     */
557    JCExpression makeLit(Type type, Object value) {
558        return make.Literal(type.getTag(), value).setType(type.constType(value));
559    }
560
561    /** Make an attributed tree representing null.
562     */
563    JCExpression makeNull() {
564        return makeLit(syms.botType, null);
565    }
566
567    /** Make an attributed class instance creation expression.
568     *  @param ctype    The class type.
569     *  @param args     The constructor arguments.
570     */
571    JCNewClass makeNewClass(Type ctype, List<JCExpression> args) {
572        JCNewClass tree = make.NewClass(null,
573            null, make.QualIdent(ctype.tsym), args, null);
574        tree.constructor = rs.resolveConstructor(
575            make_pos, attrEnv, ctype, TreeInfo.types(args), List.nil());
576        tree.type = ctype;
577        return tree;
578    }
579
580    /** Make an attributed unary expression.
581     *  @param optag    The operators tree tag.
582     *  @param arg      The operator's argument.
583     */
584    JCUnary makeUnary(JCTree.Tag optag, JCExpression arg) {
585        JCUnary tree = make.Unary(optag, arg);
586        tree.operator = operators.resolveUnary(tree, optag, arg.type);
587        tree.type = tree.operator.type.getReturnType();
588        return tree;
589    }
590
591    /** Make an attributed binary expression.
592     *  @param optag    The operators tree tag.
593     *  @param lhs      The operator's left argument.
594     *  @param rhs      The operator's right argument.
595     */
596    JCBinary makeBinary(JCTree.Tag optag, JCExpression lhs, JCExpression rhs) {
597        JCBinary tree = make.Binary(optag, lhs, rhs);
598        tree.operator = operators.resolveBinary(tree, optag, lhs.type, rhs.type);
599        tree.type = tree.operator.type.getReturnType();
600        return tree;
601    }
602
603    /** Make an attributed assignop expression.
604     *  @param optag    The operators tree tag.
605     *  @param lhs      The operator's left argument.
606     *  @param rhs      The operator's right argument.
607     */
608    JCAssignOp makeAssignop(JCTree.Tag optag, JCTree lhs, JCTree rhs) {
609        JCAssignOp tree = make.Assignop(optag, lhs, rhs);
610        tree.operator = operators.resolveBinary(tree, tree.getTag().noAssignOp(), lhs.type, rhs.type);
611        tree.type = lhs.type;
612        return tree;
613    }
614
615    /** Convert tree into string object, unless it has already a
616     *  reference type..
617     */
618    JCExpression makeString(JCExpression tree) {
619        if (!tree.type.isPrimitiveOrVoid()) {
620            return tree;
621        } else {
622            Symbol valueOfSym = lookupMethod(tree.pos(),
623                                             names.valueOf,
624                                             syms.stringType,
625                                             List.of(tree.type));
626            return make.App(make.QualIdent(valueOfSym), List.of(tree));
627        }
628    }
629
630    /** Create an empty anonymous class definition and enter and complete
631     *  its symbol. Return the class definition's symbol.
632     *  and create
633     *  @param flags    The class symbol's flags
634     *  @param owner    The class symbol's owner
635     */
636    JCClassDecl makeEmptyClass(long flags, ClassSymbol owner) {
637        return makeEmptyClass(flags, owner, null, true);
638    }
639
640    JCClassDecl makeEmptyClass(long flags, ClassSymbol owner, Name flatname,
641            boolean addToDefs) {
642        // Create class symbol.
643        ClassSymbol c = syms.defineClass(names.empty, owner);
644        if (flatname != null) {
645            c.flatname = flatname;
646        } else {
647            c.flatname = chk.localClassName(c);
648        }
649        c.sourcefile = owner.sourcefile;
650        c.completer = Completer.NULL_COMPLETER;
651        c.members_field = WriteableScope.create(c);
652        c.flags_field = flags;
653        ClassType ctype = (ClassType) c.type;
654        ctype.supertype_field = syms.objectType;
655        ctype.interfaces_field = List.nil();
656
657        JCClassDecl odef = classDef(owner);
658
659        // Enter class symbol in owner scope and compiled table.
660        enterSynthetic(odef.pos(), c, owner.members());
661        chk.putCompiled(c);
662
663        // Create class definition tree.
664        JCClassDecl cdef = make.ClassDef(
665            make.Modifiers(flags), names.empty,
666            List.nil(),
667            null, List.nil(), List.nil());
668        cdef.sym = c;
669        cdef.type = c.type;
670
671        // Append class definition tree to owner's definitions.
672        if (addToDefs) odef.defs = odef.defs.prepend(cdef);
673        return cdef;
674    }
675
676/**************************************************************************
677 * Symbol manipulation utilities
678 *************************************************************************/
679
680    /** Enter a synthetic symbol in a given scope, but complain if there was already one there.
681     *  @param pos           Position for error reporting.
682     *  @param sym           The symbol.
683     *  @param s             The scope.
684     */
685    private void enterSynthetic(DiagnosticPosition pos, Symbol sym, WriteableScope s) {
686        s.enter(sym);
687    }
688
689    /** Create a fresh synthetic name within a given scope - the unique name is
690     *  obtained by appending '$' chars at the end of the name until no match
691     *  is found.
692     *
693     * @param name base name
694     * @param s scope in which the name has to be unique
695     * @return fresh synthetic name
696     */
697    private Name makeSyntheticName(Name name, Scope s) {
698        do {
699            name = name.append(
700                    target.syntheticNameChar(),
701                    names.empty);
702        } while (lookupSynthetic(name, s) != null);
703        return name;
704    }
705
706    /** Check whether synthetic symbols generated during lowering conflict
707     *  with user-defined symbols.
708     *
709     *  @param translatedTrees lowered class trees
710     */
711    void checkConflicts(List<JCTree> translatedTrees) {
712        for (JCTree t : translatedTrees) {
713            t.accept(conflictsChecker);
714        }
715    }
716
717    JCTree.Visitor conflictsChecker = new TreeScanner() {
718
719        TypeSymbol currentClass;
720
721        @Override
722        public void visitMethodDef(JCMethodDecl that) {
723            chk.checkConflicts(that.pos(), that.sym, currentClass);
724            super.visitMethodDef(that);
725        }
726
727        @Override
728        public void visitVarDef(JCVariableDecl that) {
729            if (that.sym.owner.kind == TYP) {
730                chk.checkConflicts(that.pos(), that.sym, currentClass);
731            }
732            super.visitVarDef(that);
733        }
734
735        @Override
736        public void visitClassDef(JCClassDecl that) {
737            TypeSymbol prevCurrentClass = currentClass;
738            currentClass = that.sym;
739            try {
740                super.visitClassDef(that);
741            }
742            finally {
743                currentClass = prevCurrentClass;
744            }
745        }
746    };
747
748    /** Look up a synthetic name in a given scope.
749     *  @param s            The scope.
750     *  @param name         The name.
751     */
752    private Symbol lookupSynthetic(Name name, Scope s) {
753        Symbol sym = s.findFirst(name);
754        return (sym==null || (sym.flags()&SYNTHETIC)==0) ? null : sym;
755    }
756
757    /** Look up a method in a given scope.
758     */
759    private MethodSymbol lookupMethod(DiagnosticPosition pos, Name name, Type qual, List<Type> args) {
760        return rs.resolveInternalMethod(pos, attrEnv, qual, name, args, List.nil());
761    }
762
763    /** Anon inner classes are used as access constructor tags.
764     * accessConstructorTag will use an existing anon class if one is available,
765     * and synthethise a class (with makeEmptyClass) if one is not available.
766     * However, there is a small possibility that an existing class will not
767     * be generated as expected if it is inside a conditional with a constant
768     * expression. If that is found to be the case, create an empty class tree here.
769     */
770    private void checkAccessConstructorTags() {
771        for (List<ClassSymbol> l = accessConstrTags; l.nonEmpty(); l = l.tail) {
772            ClassSymbol c = l.head;
773            if (isTranslatedClassAvailable(c))
774                continue;
775            // Create class definition tree.
776            JCClassDecl cdec = makeEmptyClass(STATIC | SYNTHETIC,
777                    c.outermostClass(), c.flatname, false);
778            swapAccessConstructorTag(c, cdec.sym);
779            translated.append(cdec);
780        }
781    }
782    // where
783    private boolean isTranslatedClassAvailable(ClassSymbol c) {
784        for (JCTree tree: translated) {
785            if (tree.hasTag(CLASSDEF)
786                    && ((JCClassDecl) tree).sym == c) {
787                return true;
788            }
789        }
790        return false;
791    }
792
793    void swapAccessConstructorTag(ClassSymbol oldCTag, ClassSymbol newCTag) {
794        for (MethodSymbol methodSymbol : accessConstrs.values()) {
795            Assert.check(methodSymbol.type.hasTag(METHOD));
796            MethodType oldMethodType =
797                    (MethodType)methodSymbol.type;
798            if (oldMethodType.argtypes.head.tsym == oldCTag)
799                methodSymbol.type =
800                    types.createMethodTypeWithParameters(oldMethodType,
801                        oldMethodType.getParameterTypes().tail
802                            .prepend(newCTag.erasure(types)));
803        }
804    }
805
806/**************************************************************************
807 * Access methods
808 *************************************************************************/
809
810    /** A mapping from symbols to their access numbers.
811     */
812    private Map<Symbol,Integer> accessNums;
813
814    /** A mapping from symbols to an array of access symbols, indexed by
815     *  access code.
816     */
817    private Map<Symbol,MethodSymbol[]> accessSyms;
818
819    /** A mapping from (constructor) symbols to access constructor symbols.
820     */
821    private Map<Symbol,MethodSymbol> accessConstrs;
822
823    /** A list of all class symbols used for access constructor tags.
824     */
825    private List<ClassSymbol> accessConstrTags;
826
827    /** A queue for all accessed symbols.
828     */
829    private ListBuffer<Symbol> accessed;
830
831    /** return access code for identifier,
832     *  @param tree     The tree representing the identifier use.
833     *  @param enclOp   The closest enclosing operation node of tree,
834     *                  null if tree is not a subtree of an operation.
835     */
836    private static int accessCode(JCTree tree, JCTree enclOp) {
837        if (enclOp == null)
838            return AccessCode.DEREF.code;
839        else if (enclOp.hasTag(ASSIGN) &&
840                 tree == TreeInfo.skipParens(((JCAssign) enclOp).lhs))
841            return AccessCode.ASSIGN.code;
842        else if ((enclOp.getTag().isIncOrDecUnaryOp() || enclOp.getTag().isAssignop()) &&
843                tree == TreeInfo.skipParens(((JCOperatorExpression) enclOp).getOperand(LEFT)))
844            return (((JCOperatorExpression) enclOp).operator).getAccessCode(enclOp.getTag());
845        else
846            return AccessCode.DEREF.code;
847    }
848
849    /** Return binary operator that corresponds to given access code.
850     */
851    private OperatorSymbol binaryAccessOperator(int acode, Tag tag) {
852        return operators.lookupBinaryOp(op -> op.getAccessCode(tag) == acode);
853    }
854
855    /** Return tree tag for assignment operation corresponding
856     *  to given binary operator.
857     */
858    private static JCTree.Tag treeTag(OperatorSymbol operator) {
859        switch (operator.opcode) {
860        case ByteCodes.ior: case ByteCodes.lor:
861            return BITOR_ASG;
862        case ByteCodes.ixor: case ByteCodes.lxor:
863            return BITXOR_ASG;
864        case ByteCodes.iand: case ByteCodes.land:
865            return BITAND_ASG;
866        case ByteCodes.ishl: case ByteCodes.lshl:
867        case ByteCodes.ishll: case ByteCodes.lshll:
868            return SL_ASG;
869        case ByteCodes.ishr: case ByteCodes.lshr:
870        case ByteCodes.ishrl: case ByteCodes.lshrl:
871            return SR_ASG;
872        case ByteCodes.iushr: case ByteCodes.lushr:
873        case ByteCodes.iushrl: case ByteCodes.lushrl:
874            return USR_ASG;
875        case ByteCodes.iadd: case ByteCodes.ladd:
876        case ByteCodes.fadd: case ByteCodes.dadd:
877        case ByteCodes.string_add:
878            return PLUS_ASG;
879        case ByteCodes.isub: case ByteCodes.lsub:
880        case ByteCodes.fsub: case ByteCodes.dsub:
881            return MINUS_ASG;
882        case ByteCodes.imul: case ByteCodes.lmul:
883        case ByteCodes.fmul: case ByteCodes.dmul:
884            return MUL_ASG;
885        case ByteCodes.idiv: case ByteCodes.ldiv:
886        case ByteCodes.fdiv: case ByteCodes.ddiv:
887            return DIV_ASG;
888        case ByteCodes.imod: case ByteCodes.lmod:
889        case ByteCodes.fmod: case ByteCodes.dmod:
890            return MOD_ASG;
891        default:
892            throw new AssertionError();
893        }
894    }
895
896    /** The name of the access method with number `anum' and access code `acode'.
897     */
898    Name accessName(int anum, int acode) {
899        return names.fromString(
900            "access" + target.syntheticNameChar() + anum + acode / 10 + acode % 10);
901    }
902
903    /** Return access symbol for a private or protected symbol from an inner class.
904     *  @param sym        The accessed private symbol.
905     *  @param tree       The accessing tree.
906     *  @param enclOp     The closest enclosing operation node of tree,
907     *                    null if tree is not a subtree of an operation.
908     *  @param protAccess Is access to a protected symbol in another
909     *                    package?
910     *  @param refSuper   Is access via a (qualified) C.super?
911     */
912    MethodSymbol accessSymbol(Symbol sym, JCTree tree, JCTree enclOp,
913                              boolean protAccess, boolean refSuper) {
914        ClassSymbol accOwner = refSuper && protAccess
915            // For access via qualified super (T.super.x), place the
916            // access symbol on T.
917            ? (ClassSymbol)((JCFieldAccess) tree).selected.type.tsym
918            // Otherwise pretend that the owner of an accessed
919            // protected symbol is the enclosing class of the current
920            // class which is a subclass of the symbol's owner.
921            : accessClass(sym, protAccess, tree);
922
923        Symbol vsym = sym;
924        if (sym.owner != accOwner) {
925            vsym = sym.clone(accOwner);
926            actualSymbols.put(vsym, sym);
927        }
928
929        Integer anum              // The access number of the access method.
930            = accessNums.get(vsym);
931        if (anum == null) {
932            anum = accessed.length();
933            accessNums.put(vsym, anum);
934            accessSyms.put(vsym, new MethodSymbol[AccessCode.numberOfAccessCodes]);
935            accessed.append(vsym);
936            // System.out.println("accessing " + vsym + " in " + vsym.location());
937        }
938
939        int acode;                // The access code of the access method.
940        List<Type> argtypes;      // The argument types of the access method.
941        Type restype;             // The result type of the access method.
942        List<Type> thrown;        // The thrown exceptions of the access method.
943        switch (vsym.kind) {
944        case VAR:
945            acode = accessCode(tree, enclOp);
946            if (acode >= AccessCode.FIRSTASGOP.code) {
947                OperatorSymbol operator = binaryAccessOperator(acode, enclOp.getTag());
948                if (operator.opcode == string_add)
949                    argtypes = List.of(syms.objectType);
950                else
951                    argtypes = operator.type.getParameterTypes().tail;
952            } else if (acode == AccessCode.ASSIGN.code)
953                argtypes = List.of(vsym.erasure(types));
954            else
955                argtypes = List.nil();
956            restype = vsym.erasure(types);
957            thrown = List.nil();
958            break;
959        case MTH:
960            acode = AccessCode.DEREF.code;
961            argtypes = vsym.erasure(types).getParameterTypes();
962            restype = vsym.erasure(types).getReturnType();
963            thrown = vsym.type.getThrownTypes();
964            break;
965        default:
966            throw new AssertionError();
967        }
968
969        // For references via qualified super, increment acode by one,
970        // making it odd.
971        if (protAccess && refSuper) acode++;
972
973        // Instance access methods get instance as first parameter.
974        // For protected symbols this needs to be the instance as a member
975        // of the type containing the accessed symbol, not the class
976        // containing the access method.
977        if ((vsym.flags() & STATIC) == 0) {
978            argtypes = argtypes.prepend(vsym.owner.erasure(types));
979        }
980        MethodSymbol[] accessors = accessSyms.get(vsym);
981        MethodSymbol accessor = accessors[acode];
982        if (accessor == null) {
983            accessor = new MethodSymbol(
984                STATIC | SYNTHETIC | (accOwner.isInterface() ? PUBLIC : 0),
985                accessName(anum.intValue(), acode),
986                new MethodType(argtypes, restype, thrown, syms.methodClass),
987                accOwner);
988            enterSynthetic(tree.pos(), accessor, accOwner.members());
989            accessors[acode] = accessor;
990        }
991        return accessor;
992    }
993
994    /** The qualifier to be used for accessing a symbol in an outer class.
995     *  This is either C.sym or C.this.sym, depending on whether or not
996     *  sym is static.
997     *  @param sym   The accessed symbol.
998     */
999    JCExpression accessBase(DiagnosticPosition pos, Symbol sym) {
1000        return (sym.flags() & STATIC) != 0
1001            ? access(make.at(pos.getStartPosition()).QualIdent(sym.owner))
1002            : makeOwnerThis(pos, sym, true);
1003    }
1004
1005    /** Do we need an access method to reference private symbol?
1006     */
1007    boolean needsPrivateAccess(Symbol sym) {
1008        if ((sym.flags() & PRIVATE) == 0 || sym.owner == currentClass) {
1009            return false;
1010        } else if (sym.name == names.init && sym.owner.isLocal()) {
1011            // private constructor in local class: relax protection
1012            sym.flags_field &= ~PRIVATE;
1013            return false;
1014        } else {
1015            return true;
1016        }
1017    }
1018
1019    /** Do we need an access method to reference symbol in other package?
1020     */
1021    boolean needsProtectedAccess(Symbol sym, JCTree tree) {
1022        if ((sym.flags() & PROTECTED) == 0 ||
1023            sym.owner.owner == currentClass.owner || // fast special case
1024            sym.packge() == currentClass.packge())
1025            return false;
1026        if (!currentClass.isSubClass(sym.owner, types))
1027            return true;
1028        if ((sym.flags() & STATIC) != 0 ||
1029            !tree.hasTag(SELECT) ||
1030            TreeInfo.name(((JCFieldAccess) tree).selected) == names._super)
1031            return false;
1032        return !((JCFieldAccess) tree).selected.type.tsym.isSubClass(currentClass, types);
1033    }
1034
1035    /** The class in which an access method for given symbol goes.
1036     *  @param sym        The access symbol
1037     *  @param protAccess Is access to a protected symbol in another
1038     *                    package?
1039     */
1040    ClassSymbol accessClass(Symbol sym, boolean protAccess, JCTree tree) {
1041        if (protAccess) {
1042            Symbol qualifier = null;
1043            ClassSymbol c = currentClass;
1044            if (tree.hasTag(SELECT) && (sym.flags() & STATIC) == 0) {
1045                qualifier = ((JCFieldAccess) tree).selected.type.tsym;
1046                while (!qualifier.isSubClass(c, types)) {
1047                    c = c.owner.enclClass();
1048                }
1049                return c;
1050            } else {
1051                while (!c.isSubClass(sym.owner, types)) {
1052                    c = c.owner.enclClass();
1053                }
1054            }
1055            return c;
1056        } else {
1057            // the symbol is private
1058            return sym.owner.enclClass();
1059        }
1060    }
1061
1062    private void addPrunedInfo(JCTree tree) {
1063        List<JCTree> infoList = prunedTree.get(currentClass);
1064        infoList = (infoList == null) ? List.of(tree) : infoList.prepend(tree);
1065        prunedTree.put(currentClass, infoList);
1066    }
1067
1068    /** Ensure that identifier is accessible, return tree accessing the identifier.
1069     *  @param sym      The accessed symbol.
1070     *  @param tree     The tree referring to the symbol.
1071     *  @param enclOp   The closest enclosing operation node of tree,
1072     *                  null if tree is not a subtree of an operation.
1073     *  @param refSuper Is access via a (qualified) C.super?
1074     */
1075    JCExpression access(Symbol sym, JCExpression tree, JCExpression enclOp, boolean refSuper) {
1076        // Access a free variable via its proxy, or its proxy's proxy
1077        while (sym.kind == VAR && sym.owner.kind == MTH &&
1078            sym.owner.enclClass() != currentClass) {
1079            // A constant is replaced by its constant value.
1080            Object cv = ((VarSymbol)sym).getConstValue();
1081            if (cv != null) {
1082                make.at(tree.pos);
1083                return makeLit(sym.type, cv);
1084            }
1085            // Otherwise replace the variable by its proxy.
1086            sym = proxies.findFirst(proxyName(sym.name));
1087            Assert.check(sym != null && (sym.flags_field & FINAL) != 0);
1088            tree = make.at(tree.pos).Ident(sym);
1089        }
1090        JCExpression base = (tree.hasTag(SELECT)) ? ((JCFieldAccess) tree).selected : null;
1091        switch (sym.kind) {
1092        case TYP:
1093            if (sym.owner.kind != PCK) {
1094                // Convert type idents to
1095                // <flat name> or <package name> . <flat name>
1096                Name flatname = Convert.shortName(sym.flatName());
1097                while (base != null &&
1098                       TreeInfo.symbol(base) != null &&
1099                       TreeInfo.symbol(base).kind != PCK) {
1100                    base = (base.hasTag(SELECT))
1101                        ? ((JCFieldAccess) base).selected
1102                        : null;
1103                }
1104                if (tree.hasTag(IDENT)) {
1105                    ((JCIdent) tree).name = flatname;
1106                } else if (base == null) {
1107                    tree = make.at(tree.pos).Ident(sym);
1108                    ((JCIdent) tree).name = flatname;
1109                } else {
1110                    ((JCFieldAccess) tree).selected = base;
1111                    ((JCFieldAccess) tree).name = flatname;
1112                }
1113            }
1114            break;
1115        case MTH: case VAR:
1116            if (sym.owner.kind == TYP) {
1117
1118                // Access methods are required for
1119                //  - private members,
1120                //  - protected members in a superclass of an
1121                //    enclosing class contained in another package.
1122                //  - all non-private members accessed via a qualified super.
1123                boolean protAccess = refSuper && !needsPrivateAccess(sym)
1124                    || needsProtectedAccess(sym, tree);
1125                boolean accReq = protAccess || needsPrivateAccess(sym);
1126
1127                // A base has to be supplied for
1128                //  - simple identifiers accessing variables in outer classes.
1129                boolean baseReq =
1130                    base == null &&
1131                    sym.owner != syms.predefClass &&
1132                    !sym.isMemberOf(currentClass, types);
1133
1134                if (accReq || baseReq) {
1135                    make.at(tree.pos);
1136
1137                    // Constants are replaced by their constant value.
1138                    if (sym.kind == VAR) {
1139                        Object cv = ((VarSymbol)sym).getConstValue();
1140                        if (cv != null) {
1141                            addPrunedInfo(tree);
1142                            return makeLit(sym.type, cv);
1143                        }
1144                    }
1145
1146                    // Private variables and methods are replaced by calls
1147                    // to their access methods.
1148                    if (accReq) {
1149                        List<JCExpression> args = List.nil();
1150                        if ((sym.flags() & STATIC) == 0) {
1151                            // Instance access methods get instance
1152                            // as first parameter.
1153                            if (base == null)
1154                                base = makeOwnerThis(tree.pos(), sym, true);
1155                            args = args.prepend(base);
1156                            base = null;   // so we don't duplicate code
1157                        }
1158                        Symbol access = accessSymbol(sym, tree,
1159                                                     enclOp, protAccess,
1160                                                     refSuper);
1161                        JCExpression receiver = make.Select(
1162                            base != null ? base : make.QualIdent(access.owner),
1163                            access);
1164                        return make.App(receiver, args);
1165
1166                    // Other accesses to members of outer classes get a
1167                    // qualifier.
1168                    } else if (baseReq) {
1169                        return make.at(tree.pos).Select(
1170                            accessBase(tree.pos(), sym), sym).setType(tree.type);
1171                    }
1172                }
1173            } else if (sym.owner.kind == MTH && lambdaTranslationMap != null) {
1174                //sym is a local variable - check the lambda translation map to
1175                //see if sym has been translated to something else in the current
1176                //scope (by LambdaToMethod)
1177                Symbol translatedSym = lambdaTranslationMap.get(sym);
1178                if (translatedSym != null) {
1179                    tree = make.at(tree.pos).Ident(translatedSym);
1180                }
1181            }
1182        }
1183        return tree;
1184    }
1185
1186    /** Ensure that identifier is accessible, return tree accessing the identifier.
1187     *  @param tree     The identifier tree.
1188     */
1189    JCExpression access(JCExpression tree) {
1190        Symbol sym = TreeInfo.symbol(tree);
1191        return sym == null ? tree : access(sym, tree, null, false);
1192    }
1193
1194    /** Return access constructor for a private constructor,
1195     *  or the constructor itself, if no access constructor is needed.
1196     *  @param pos       The position to report diagnostics, if any.
1197     *  @param constr    The private constructor.
1198     */
1199    Symbol accessConstructor(DiagnosticPosition pos, Symbol constr) {
1200        if (needsPrivateAccess(constr)) {
1201            ClassSymbol accOwner = constr.owner.enclClass();
1202            MethodSymbol aconstr = accessConstrs.get(constr);
1203            if (aconstr == null) {
1204                List<Type> argtypes = constr.type.getParameterTypes();
1205                if ((accOwner.flags_field & ENUM) != 0)
1206                    argtypes = argtypes
1207                        .prepend(syms.intType)
1208                        .prepend(syms.stringType);
1209                aconstr = new MethodSymbol(
1210                    SYNTHETIC,
1211                    names.init,
1212                    new MethodType(
1213                        argtypes.append(
1214                            accessConstructorTag().erasure(types)),
1215                        constr.type.getReturnType(),
1216                        constr.type.getThrownTypes(),
1217                        syms.methodClass),
1218                    accOwner);
1219                enterSynthetic(pos, aconstr, accOwner.members());
1220                accessConstrs.put(constr, aconstr);
1221                accessed.append(constr);
1222            }
1223            return aconstr;
1224        } else {
1225            return constr;
1226        }
1227    }
1228
1229    /** Return an anonymous class nested in this toplevel class.
1230     */
1231    ClassSymbol accessConstructorTag() {
1232        ClassSymbol topClass = currentClass.outermostClass();
1233        ModuleSymbol topModle = topClass.packge().modle;
1234        Name flatname = names.fromString("" + topClass.getQualifiedName() +
1235                                         target.syntheticNameChar() +
1236                                         "1");
1237        ClassSymbol ctag = chk.getCompiled(topModle, flatname);
1238        if (ctag == null)
1239            ctag = makeEmptyClass(STATIC | SYNTHETIC, topClass).sym;
1240        // keep a record of all tags, to verify that all are generated as required
1241        accessConstrTags = accessConstrTags.prepend(ctag);
1242        return ctag;
1243    }
1244
1245    /** Add all required access methods for a private symbol to enclosing class.
1246     *  @param sym       The symbol.
1247     */
1248    void makeAccessible(Symbol sym) {
1249        JCClassDecl cdef = classDef(sym.owner.enclClass());
1250        if (cdef == null) Assert.error("class def not found: " + sym + " in " + sym.owner);
1251        if (sym.name == names.init) {
1252            cdef.defs = cdef.defs.prepend(
1253                accessConstructorDef(cdef.pos, sym, accessConstrs.get(sym)));
1254        } else {
1255            MethodSymbol[] accessors = accessSyms.get(sym);
1256            for (int i = 0; i < AccessCode.numberOfAccessCodes; i++) {
1257                if (accessors[i] != null)
1258                    cdef.defs = cdef.defs.prepend(
1259                        accessDef(cdef.pos, sym, accessors[i], i));
1260            }
1261        }
1262    }
1263
1264    /** Construct definition of an access method.
1265     *  @param pos        The source code position of the definition.
1266     *  @param vsym       The private or protected symbol.
1267     *  @param accessor   The access method for the symbol.
1268     *  @param acode      The access code.
1269     */
1270    JCTree accessDef(int pos, Symbol vsym, MethodSymbol accessor, int acode) {
1271//      System.err.println("access " + vsym + " with " + accessor);//DEBUG
1272        currentClass = vsym.owner.enclClass();
1273        make.at(pos);
1274        JCMethodDecl md = make.MethodDef(accessor, null);
1275
1276        // Find actual symbol
1277        Symbol sym = actualSymbols.get(vsym);
1278        if (sym == null) sym = vsym;
1279
1280        JCExpression ref;           // The tree referencing the private symbol.
1281        List<JCExpression> args;    // Any additional arguments to be passed along.
1282        if ((sym.flags() & STATIC) != 0) {
1283            ref = make.Ident(sym);
1284            args = make.Idents(md.params);
1285        } else {
1286            JCExpression site = make.Ident(md.params.head);
1287            if (acode % 2 != 0) {
1288                //odd access codes represent qualified super accesses - need to
1289                //emit reference to the direct superclass, even if the refered
1290                //member is from an indirect superclass (JLS 13.1)
1291                site.setType(types.erasure(types.supertype(vsym.owner.enclClass().type)));
1292            }
1293            ref = make.Select(site, sym);
1294            args = make.Idents(md.params.tail);
1295        }
1296        JCStatement stat;          // The statement accessing the private symbol.
1297        if (sym.kind == VAR) {
1298            // Normalize out all odd access codes by taking floor modulo 2:
1299            int acode1 = acode - (acode & 1);
1300
1301            JCExpression expr;      // The access method's return value.
1302            AccessCode aCode = AccessCode.getFromCode(acode1);
1303            switch (aCode) {
1304            case DEREF:
1305                expr = ref;
1306                break;
1307            case ASSIGN:
1308                expr = make.Assign(ref, args.head);
1309                break;
1310            case PREINC: case POSTINC: case PREDEC: case POSTDEC:
1311                expr = makeUnary(aCode.tag, ref);
1312                break;
1313            default:
1314                expr = make.Assignop(
1315                    treeTag(binaryAccessOperator(acode1, JCTree.Tag.NO_TAG)), ref, args.head);
1316                ((JCAssignOp) expr).operator = binaryAccessOperator(acode1, JCTree.Tag.NO_TAG);
1317            }
1318            stat = make.Return(expr.setType(sym.type));
1319        } else {
1320            stat = make.Call(make.App(ref, args));
1321        }
1322        md.body = make.Block(0, List.of(stat));
1323
1324        // Make sure all parameters, result types and thrown exceptions
1325        // are accessible.
1326        for (List<JCVariableDecl> l = md.params; l.nonEmpty(); l = l.tail)
1327            l.head.vartype = access(l.head.vartype);
1328        md.restype = access(md.restype);
1329        for (List<JCExpression> l = md.thrown; l.nonEmpty(); l = l.tail)
1330            l.head = access(l.head);
1331
1332        return md;
1333    }
1334
1335    /** Construct definition of an access constructor.
1336     *  @param pos        The source code position of the definition.
1337     *  @param constr     The private constructor.
1338     *  @param accessor   The access method for the constructor.
1339     */
1340    JCTree accessConstructorDef(int pos, Symbol constr, MethodSymbol accessor) {
1341        make.at(pos);
1342        JCMethodDecl md = make.MethodDef(accessor,
1343                                      accessor.externalType(types),
1344                                      null);
1345        JCIdent callee = make.Ident(names._this);
1346        callee.sym = constr;
1347        callee.type = constr.type;
1348        md.body =
1349            make.Block(0, List.of(
1350                make.Call(
1351                    make.App(
1352                        callee,
1353                        make.Idents(md.params.reverse().tail.reverse())))));
1354        return md;
1355    }
1356
1357/**************************************************************************
1358 * Free variables proxies and this$n
1359 *************************************************************************/
1360
1361    /** A scope containing all free variable proxies for currently translated
1362     *  class, as well as its this$n symbol (if needed).
1363     *  Proxy scopes are nested in the same way classes are.
1364     *  Inside a constructor, proxies and any this$n symbol are duplicated
1365     *  in an additional innermost scope, where they represent the constructor
1366     *  parameters.
1367     */
1368    WriteableScope proxies;
1369
1370    /** A scope containing all unnamed resource variables/saved
1371     *  exception variables for translated TWR blocks
1372     */
1373    WriteableScope twrVars;
1374
1375    /** A stack containing the this$n field of the currently translated
1376     *  classes (if needed) in innermost first order.
1377     *  Inside a constructor, proxies and any this$n symbol are duplicated
1378     *  in an additional innermost scope, where they represent the constructor
1379     *  parameters.
1380     */
1381    List<VarSymbol> outerThisStack;
1382
1383    /** The name of a free variable proxy.
1384     */
1385    Name proxyName(Name name) {
1386        return names.fromString("val" + target.syntheticNameChar() + name);
1387    }
1388
1389    /** Proxy definitions for all free variables in given list, in reverse order.
1390     *  @param pos        The source code position of the definition.
1391     *  @param freevars   The free variables.
1392     *  @param owner      The class in which the definitions go.
1393     */
1394    List<JCVariableDecl> freevarDefs(int pos, List<VarSymbol> freevars, Symbol owner) {
1395        return freevarDefs(pos, freevars, owner, 0);
1396    }
1397
1398    List<JCVariableDecl> freevarDefs(int pos, List<VarSymbol> freevars, Symbol owner,
1399            long additionalFlags) {
1400        long flags = FINAL | SYNTHETIC | additionalFlags;
1401        List<JCVariableDecl> defs = List.nil();
1402        for (List<VarSymbol> l = freevars; l.nonEmpty(); l = l.tail) {
1403            VarSymbol v = l.head;
1404            VarSymbol proxy = new VarSymbol(
1405                flags, proxyName(v.name), v.erasure(types), owner);
1406            proxies.enter(proxy);
1407            JCVariableDecl vd = make.at(pos).VarDef(proxy, null);
1408            vd.vartype = access(vd.vartype);
1409            defs = defs.prepend(vd);
1410        }
1411        return defs;
1412    }
1413
1414    /** The name of a this$n field
1415     *  @param type   The class referenced by the this$n field
1416     */
1417    Name outerThisName(Type type, Symbol owner) {
1418        Type t = type.getEnclosingType();
1419        int nestingLevel = 0;
1420        while (t.hasTag(CLASS)) {
1421            t = t.getEnclosingType();
1422            nestingLevel++;
1423        }
1424        Name result = names.fromString("this" + target.syntheticNameChar() + nestingLevel);
1425        while (owner.kind == TYP && ((ClassSymbol)owner).members().findFirst(result) != null)
1426            result = names.fromString(result.toString() + target.syntheticNameChar());
1427        return result;
1428    }
1429
1430    private VarSymbol makeOuterThisVarSymbol(Symbol owner, long flags) {
1431        Type target = types.erasure(owner.enclClass().type.getEnclosingType());
1432        VarSymbol outerThis =
1433            new VarSymbol(flags, outerThisName(target, owner), target, owner);
1434        outerThisStack = outerThisStack.prepend(outerThis);
1435        return outerThis;
1436    }
1437
1438    private JCVariableDecl makeOuterThisVarDecl(int pos, VarSymbol sym) {
1439        JCVariableDecl vd = make.at(pos).VarDef(sym, null);
1440        vd.vartype = access(vd.vartype);
1441        return vd;
1442    }
1443
1444    /** Definition for this$n field.
1445     *  @param pos        The source code position of the definition.
1446     *  @param owner      The method in which the definition goes.
1447     */
1448    JCVariableDecl outerThisDef(int pos, MethodSymbol owner) {
1449        ClassSymbol c = owner.enclClass();
1450        boolean isMandated =
1451            // Anonymous constructors
1452            (owner.isConstructor() && owner.isAnonymous()) ||
1453            // Constructors of non-private inner member classes
1454            (owner.isConstructor() && c.isInner() &&
1455             !c.isPrivate() && !c.isStatic());
1456        long flags =
1457            FINAL | (isMandated ? MANDATED : SYNTHETIC) | PARAMETER;
1458        VarSymbol outerThis = makeOuterThisVarSymbol(owner, flags);
1459        owner.extraParams = owner.extraParams.prepend(outerThis);
1460        return makeOuterThisVarDecl(pos, outerThis);
1461    }
1462
1463    /** Definition for this$n field.
1464     *  @param pos        The source code position of the definition.
1465     *  @param owner      The class in which the definition goes.
1466     */
1467    JCVariableDecl outerThisDef(int pos, ClassSymbol owner) {
1468        VarSymbol outerThis = makeOuterThisVarSymbol(owner, FINAL | SYNTHETIC);
1469        return makeOuterThisVarDecl(pos, outerThis);
1470    }
1471
1472    /** Return a list of trees that load the free variables in given list,
1473     *  in reverse order.
1474     *  @param pos          The source code position to be used for the trees.
1475     *  @param freevars     The list of free variables.
1476     */
1477    List<JCExpression> loadFreevars(DiagnosticPosition pos, List<VarSymbol> freevars) {
1478        List<JCExpression> args = List.nil();
1479        for (List<VarSymbol> l = freevars; l.nonEmpty(); l = l.tail)
1480            args = args.prepend(loadFreevar(pos, l.head));
1481        return args;
1482    }
1483//where
1484        JCExpression loadFreevar(DiagnosticPosition pos, VarSymbol v) {
1485            return access(v, make.at(pos).Ident(v), null, false);
1486        }
1487
1488    /** Construct a tree simulating the expression {@code C.this}.
1489     *  @param pos           The source code position to be used for the tree.
1490     *  @param c             The qualifier class.
1491     */
1492    JCExpression makeThis(DiagnosticPosition pos, TypeSymbol c) {
1493        if (currentClass == c) {
1494            // in this case, `this' works fine
1495            return make.at(pos).This(c.erasure(types));
1496        } else {
1497            // need to go via this$n
1498            return makeOuterThis(pos, c);
1499        }
1500    }
1501
1502    /**
1503     * Optionally replace a try statement with the desugaring of a
1504     * try-with-resources statement.  The canonical desugaring of
1505     *
1506     * try ResourceSpecification
1507     *   Block
1508     *
1509     * is
1510     *
1511     * {
1512     *   final VariableModifiers_minus_final R #resource = Expression;
1513     *   Throwable #primaryException = null;
1514     *
1515     *   try ResourceSpecificationtail
1516     *     Block
1517     *   catch (Throwable #t) {
1518     *     #primaryException = t;
1519     *     throw #t;
1520     *   } finally {
1521     *     if (#resource != null) {
1522     *       if (#primaryException != null) {
1523     *         try {
1524     *           #resource.close();
1525     *         } catch(Throwable #suppressedException) {
1526     *           #primaryException.addSuppressed(#suppressedException);
1527     *         }
1528     *       } else {
1529     *         #resource.close();
1530     *       }
1531     *     }
1532     *   }
1533     *
1534     * @param tree  The try statement to inspect.
1535     * @return A a desugared try-with-resources tree, or the original
1536     * try block if there are no resources to manage.
1537     */
1538    JCTree makeTwrTry(JCTry tree) {
1539        make_at(tree.pos());
1540        twrVars = twrVars.dup();
1541        JCBlock twrBlock = makeTwrBlock(tree.resources, tree.body,
1542                tree.finallyCanCompleteNormally, 0);
1543        if (tree.catchers.isEmpty() && tree.finalizer == null)
1544            result = translate(twrBlock);
1545        else
1546            result = translate(make.Try(twrBlock, tree.catchers, tree.finalizer));
1547        twrVars = twrVars.leave();
1548        return result;
1549    }
1550
1551    private JCBlock makeTwrBlock(List<JCTree> resources, JCBlock block,
1552            boolean finallyCanCompleteNormally, int depth) {
1553        if (resources.isEmpty())
1554            return block;
1555
1556        // Add resource declaration or expression to block statements
1557        ListBuffer<JCStatement> stats = new ListBuffer<>();
1558        JCTree resource = resources.head;
1559        JCExpression expr = null;
1560        boolean resourceNonNull;
1561        if (resource instanceof JCVariableDecl) {
1562            JCVariableDecl var = (JCVariableDecl) resource;
1563            expr = make.Ident(var.sym).setType(resource.type);
1564            resourceNonNull = var.init != null && TreeInfo.skipParens(var.init).hasTag(NEWCLASS);
1565            stats.add(var);
1566        } else {
1567            Assert.check(resource instanceof JCExpression);
1568            VarSymbol syntheticTwrVar =
1569            new VarSymbol(SYNTHETIC | FINAL,
1570                          makeSyntheticName(names.fromString("twrVar" +
1571                                           depth), twrVars),
1572                          (resource.type.hasTag(BOT)) ?
1573                          syms.autoCloseableType : resource.type,
1574                          currentMethodSym);
1575            twrVars.enter(syntheticTwrVar);
1576            JCVariableDecl syntheticTwrVarDecl =
1577                make.VarDef(syntheticTwrVar, (JCExpression)resource);
1578            expr = (JCExpression)make.Ident(syntheticTwrVar);
1579            resourceNonNull = TreeInfo.skipParens(resource).hasTag(NEWCLASS);
1580            stats.add(syntheticTwrVarDecl);
1581        }
1582
1583        // Add primaryException declaration
1584        VarSymbol primaryException =
1585            new VarSymbol(SYNTHETIC,
1586                          makeSyntheticName(names.fromString("primaryException" +
1587                          depth), twrVars),
1588                          syms.throwableType,
1589                          currentMethodSym);
1590        twrVars.enter(primaryException);
1591        JCVariableDecl primaryExceptionTreeDecl = make.VarDef(primaryException, makeNull());
1592        stats.add(primaryExceptionTreeDecl);
1593
1594        // Create catch clause that saves exception and then rethrows it
1595        VarSymbol param =
1596            new VarSymbol(FINAL|SYNTHETIC,
1597                          names.fromString("t" +
1598                                           target.syntheticNameChar()),
1599                          syms.throwableType,
1600                          currentMethodSym);
1601        JCVariableDecl paramTree = make.VarDef(param, null);
1602        JCStatement assign = make.Assignment(primaryException, make.Ident(param));
1603        JCStatement rethrowStat = make.Throw(make.Ident(param));
1604        JCBlock catchBlock = make.Block(0L, List.of(assign, rethrowStat));
1605        JCCatch catchClause = make.Catch(paramTree, catchBlock);
1606
1607        int oldPos = make.pos;
1608        make.at(TreeInfo.endPos(block));
1609        JCBlock finallyClause = makeTwrFinallyClause(primaryException, expr, resourceNonNull);
1610        make.at(oldPos);
1611        JCTry outerTry = make.Try(makeTwrBlock(resources.tail, block,
1612                                    finallyCanCompleteNormally, depth + 1),
1613                                  List.of(catchClause),
1614                                  finallyClause);
1615        outerTry.finallyCanCompleteNormally = finallyCanCompleteNormally;
1616        stats.add(outerTry);
1617        JCBlock newBlock = make.Block(0L, stats.toList());
1618        return newBlock;
1619    }
1620
1621    /**If the estimated number of copies the close resource code in a single class is above this
1622     * threshold, generate and use a method for the close resource code, leading to smaller code.
1623     * As generating a method has overhead on its own, generating the method for cases below the
1624     * threshold could lead to an increase in code size.
1625     */
1626    public static final int USE_CLOSE_RESOURCE_METHOD_THRESHOLD = 4;
1627
1628    private JCBlock makeTwrFinallyClause(Symbol primaryException, JCExpression resource,
1629            boolean resourceNonNull) {
1630        MethodSymbol closeResource = (MethodSymbol)lookupSynthetic(dollarCloseResource,
1631                                                                   currentClass.members());
1632
1633        if (closeResource == null && shouldUseCloseResourceMethod()) {
1634            closeResource = new MethodSymbol(
1635                PRIVATE | STATIC | SYNTHETIC,
1636                dollarCloseResource,
1637                new MethodType(
1638                    List.of(syms.throwableType, syms.autoCloseableType),
1639                    syms.voidType,
1640                    List.nil(),
1641                    syms.methodClass),
1642                currentClass);
1643            enterSynthetic(resource.pos(), closeResource, currentClass.members());
1644
1645            JCMethodDecl md = make.MethodDef(closeResource, null);
1646            List<JCVariableDecl> params = md.getParameters();
1647            md.body = make.Block(0, List.of(makeTwrCloseStatement(params.get(0).sym,
1648                                                                               make.Ident(params.get(1)))));
1649
1650            JCClassDecl currentClassDecl = classDef(currentClass);
1651            currentClassDecl.defs = currentClassDecl.defs.prepend(md);
1652        }
1653
1654        JCStatement closeStatement;
1655
1656        if (closeResource != null) {
1657            //$closeResource(#primaryException, #resource)
1658            closeStatement = make.Exec(make.Apply(List.nil(),
1659                                                  make.Ident(closeResource),
1660                                                  List.of(make.Ident(primaryException),
1661                                                          resource)
1662                                                 ).setType(syms.voidType));
1663        } else {
1664            closeStatement = makeTwrCloseStatement(primaryException, resource);
1665        }
1666
1667        JCStatement finallyStatement;
1668
1669        if (resourceNonNull) {
1670            finallyStatement = closeStatement;
1671        } else {
1672            // if (#resource != null) { $closeResource(...); }
1673            finallyStatement = make.If(makeNonNullCheck(resource),
1674                                       closeStatement,
1675                                       null);
1676        }
1677
1678        return make.Block(0L,
1679                          List.of(finallyStatement));
1680    }
1681        //where:
1682        private boolean shouldUseCloseResourceMethod() {
1683            class TryFinder extends TreeScanner {
1684                int closeCount;
1685                @Override
1686                public void visitTry(JCTry tree) {
1687                    boolean empty = tree.body.stats.isEmpty();
1688
1689                    for (JCTree r : tree.resources) {
1690                        closeCount += empty ? 1 : 2;
1691                        empty = false; //with multiple resources, only the innermost try can be empty.
1692                    }
1693                    super.visitTry(tree);
1694                }
1695                @Override
1696                public void scan(JCTree tree) {
1697                    if (useCloseResourceMethod())
1698                        return;
1699                    super.scan(tree);
1700                }
1701                boolean useCloseResourceMethod() {
1702                    return closeCount >= USE_CLOSE_RESOURCE_METHOD_THRESHOLD;
1703                }
1704            }
1705            TryFinder tryFinder = new TryFinder();
1706            tryFinder.scan(classDef(currentClass));
1707            return tryFinder.useCloseResourceMethod();
1708        }
1709
1710    private JCStatement makeTwrCloseStatement(Symbol primaryException, JCExpression resource) {
1711        // primaryException.addSuppressed(catchException);
1712        VarSymbol catchException =
1713            new VarSymbol(SYNTHETIC, make.paramName(2),
1714                          syms.throwableType,
1715                          currentMethodSym);
1716        JCStatement addSuppressionStatement =
1717            make.Exec(makeCall(make.Ident(primaryException),
1718                               names.addSuppressed,
1719                               List.of(make.Ident(catchException))));
1720
1721        // try { resource.close(); } catch (e) { primaryException.addSuppressed(e); }
1722        JCBlock tryBlock =
1723            make.Block(0L, List.of(makeResourceCloseInvocation(resource)));
1724        JCVariableDecl catchExceptionDecl = make.VarDef(catchException, null);
1725        JCBlock catchBlock = make.Block(0L, List.of(addSuppressionStatement));
1726        List<JCCatch> catchClauses = List.of(make.Catch(catchExceptionDecl, catchBlock));
1727        JCTry tryTree = make.Try(tryBlock, catchClauses, null);
1728        tryTree.finallyCanCompleteNormally = true;
1729
1730        // if (primaryException != null) {try...} else resourceClose;
1731        JCIf closeIfStatement = make.If(makeNonNullCheck(make.Ident(primaryException)),
1732                                        tryTree,
1733                                        makeResourceCloseInvocation(resource));
1734
1735        return closeIfStatement;
1736    }
1737
1738    private JCStatement makeResourceCloseInvocation(JCExpression resource) {
1739        // convert to AutoCloseable if needed
1740        if (types.asSuper(resource.type, syms.autoCloseableType.tsym) == null) {
1741            resource = convert(resource, syms.autoCloseableType);
1742        }
1743
1744        // create resource.close() method invocation
1745        JCExpression resourceClose = makeCall(resource,
1746                                              names.close,
1747                                              List.nil());
1748        return make.Exec(resourceClose);
1749    }
1750
1751    private JCExpression makeNonNullCheck(JCExpression expression) {
1752        return makeBinary(NE, expression, makeNull());
1753    }
1754
1755    /** Construct a tree that represents the outer instance
1756     *  {@code C.this}. Never pick the current `this'.
1757     *  @param pos           The source code position to be used for the tree.
1758     *  @param c             The qualifier class.
1759     */
1760    JCExpression makeOuterThis(DiagnosticPosition pos, TypeSymbol c) {
1761        List<VarSymbol> ots = outerThisStack;
1762        if (ots.isEmpty()) {
1763            log.error(pos, "no.encl.instance.of.type.in.scope", c);
1764            Assert.error();
1765            return makeNull();
1766        }
1767        VarSymbol ot = ots.head;
1768        JCExpression tree = access(make.at(pos).Ident(ot));
1769        TypeSymbol otc = ot.type.tsym;
1770        while (otc != c) {
1771            do {
1772                ots = ots.tail;
1773                if (ots.isEmpty()) {
1774                    log.error(pos,
1775                              "no.encl.instance.of.type.in.scope",
1776                              c);
1777                    Assert.error(); // should have been caught in Attr
1778                    return tree;
1779                }
1780                ot = ots.head;
1781            } while (ot.owner != otc);
1782            if (otc.owner.kind != PCK && !otc.hasOuterInstance()) {
1783                chk.earlyRefError(pos, c);
1784                Assert.error(); // should have been caught in Attr
1785                return makeNull();
1786            }
1787            tree = access(make.at(pos).Select(tree, ot));
1788            otc = ot.type.tsym;
1789        }
1790        return tree;
1791    }
1792
1793    /** Construct a tree that represents the closest outer instance
1794     *  {@code C.this} such that the given symbol is a member of C.
1795     *  @param pos           The source code position to be used for the tree.
1796     *  @param sym           The accessed symbol.
1797     *  @param preciseMatch  should we accept a type that is a subtype of
1798     *                       sym's owner, even if it doesn't contain sym
1799     *                       due to hiding, overriding, or non-inheritance
1800     *                       due to protection?
1801     */
1802    JCExpression makeOwnerThis(DiagnosticPosition pos, Symbol sym, boolean preciseMatch) {
1803        Symbol c = sym.owner;
1804        if (preciseMatch ? sym.isMemberOf(currentClass, types)
1805                         : currentClass.isSubClass(sym.owner, types)) {
1806            // in this case, `this' works fine
1807            return make.at(pos).This(c.erasure(types));
1808        } else {
1809            // need to go via this$n
1810            return makeOwnerThisN(pos, sym, preciseMatch);
1811        }
1812    }
1813
1814    /**
1815     * Similar to makeOwnerThis but will never pick "this".
1816     */
1817    JCExpression makeOwnerThisN(DiagnosticPosition pos, Symbol sym, boolean preciseMatch) {
1818        Symbol c = sym.owner;
1819        List<VarSymbol> ots = outerThisStack;
1820        if (ots.isEmpty()) {
1821            log.error(pos, "no.encl.instance.of.type.in.scope", c);
1822            Assert.error();
1823            return makeNull();
1824        }
1825        VarSymbol ot = ots.head;
1826        JCExpression tree = access(make.at(pos).Ident(ot));
1827        TypeSymbol otc = ot.type.tsym;
1828        while (!(preciseMatch ? sym.isMemberOf(otc, types) : otc.isSubClass(sym.owner, types))) {
1829            do {
1830                ots = ots.tail;
1831                if (ots.isEmpty()) {
1832                    log.error(pos,
1833                        "no.encl.instance.of.type.in.scope",
1834                        c);
1835                    Assert.error();
1836                    return tree;
1837                }
1838                ot = ots.head;
1839            } while (ot.owner != otc);
1840            tree = access(make.at(pos).Select(tree, ot));
1841            otc = ot.type.tsym;
1842        }
1843        return tree;
1844    }
1845
1846    /** Return tree simulating the assignment {@code this.name = name}, where
1847     *  name is the name of a free variable.
1848     */
1849    JCStatement initField(int pos, Name name) {
1850        Iterator<Symbol> it = proxies.getSymbolsByName(name).iterator();
1851        Symbol rhs = it.next();
1852        Assert.check(rhs.owner.kind == MTH);
1853        Symbol lhs = it.next();
1854        Assert.check(rhs.owner.owner == lhs.owner);
1855        make.at(pos);
1856        return
1857            make.Exec(
1858                make.Assign(
1859                    make.Select(make.This(lhs.owner.erasure(types)), lhs),
1860                    make.Ident(rhs)).setType(lhs.erasure(types)));
1861    }
1862
1863    /** Return tree simulating the assignment {@code this.this$n = this$n}.
1864     */
1865    JCStatement initOuterThis(int pos) {
1866        VarSymbol rhs = outerThisStack.head;
1867        Assert.check(rhs.owner.kind == MTH);
1868        VarSymbol lhs = outerThisStack.tail.head;
1869        Assert.check(rhs.owner.owner == lhs.owner);
1870        make.at(pos);
1871        return
1872            make.Exec(
1873                make.Assign(
1874                    make.Select(make.This(lhs.owner.erasure(types)), lhs),
1875                    make.Ident(rhs)).setType(lhs.erasure(types)));
1876    }
1877
1878/**************************************************************************
1879 * Code for .class
1880 *************************************************************************/
1881
1882    /** Return the symbol of a class to contain a cache of
1883     *  compiler-generated statics such as class$ and the
1884     *  $assertionsDisabled flag.  We create an anonymous nested class
1885     *  (unless one already exists) and return its symbol.  However,
1886     *  for backward compatibility in 1.4 and earlier we use the
1887     *  top-level class itself.
1888     */
1889    private ClassSymbol outerCacheClass() {
1890        ClassSymbol clazz = outermostClassDef.sym;
1891        Scope s = clazz.members();
1892        for (Symbol sym : s.getSymbols(NON_RECURSIVE))
1893            if (sym.kind == TYP &&
1894                sym.name == names.empty &&
1895                (sym.flags() & INTERFACE) == 0) return (ClassSymbol) sym;
1896        return makeEmptyClass(STATIC | SYNTHETIC, clazz).sym;
1897    }
1898
1899    /** Create an attributed tree of the form left.name(). */
1900    private JCMethodInvocation makeCall(JCExpression left, Name name, List<JCExpression> args) {
1901        Assert.checkNonNull(left.type);
1902        Symbol funcsym = lookupMethod(make_pos, name, left.type,
1903                                      TreeInfo.types(args));
1904        return make.App(make.Select(left, funcsym), args);
1905    }
1906
1907    /** The tree simulating a T.class expression.
1908     *  @param clazz      The tree identifying type T.
1909     */
1910    private JCExpression classOf(JCTree clazz) {
1911        return classOfType(clazz.type, clazz.pos());
1912    }
1913
1914    private JCExpression classOfType(Type type, DiagnosticPosition pos) {
1915        switch (type.getTag()) {
1916        case BYTE: case SHORT: case CHAR: case INT: case LONG: case FLOAT:
1917        case DOUBLE: case BOOLEAN: case VOID:
1918            // replace with <BoxedClass>.TYPE
1919            ClassSymbol c = types.boxedClass(type);
1920            Symbol typeSym =
1921                rs.accessBase(
1922                    rs.findIdentInType(attrEnv, c.type, names.TYPE, KindSelector.VAR),
1923                    pos, c.type, names.TYPE, true);
1924            if (typeSym.kind == VAR)
1925                ((VarSymbol)typeSym).getConstValue(); // ensure initializer is evaluated
1926            return make.QualIdent(typeSym);
1927        case CLASS: case ARRAY:
1928                VarSymbol sym = new VarSymbol(
1929                        STATIC | PUBLIC | FINAL, names._class,
1930                        syms.classType, type.tsym);
1931                return make_at(pos).Select(make.Type(type), sym);
1932        default:
1933            throw new AssertionError();
1934        }
1935    }
1936
1937/**************************************************************************
1938 * Code for enabling/disabling assertions.
1939 *************************************************************************/
1940
1941    private ClassSymbol assertionsDisabledClassCache;
1942
1943    /**Used to create an auxiliary class to hold $assertionsDisabled for interfaces.
1944     */
1945    private ClassSymbol assertionsDisabledClass() {
1946        if (assertionsDisabledClassCache != null) return assertionsDisabledClassCache;
1947
1948        assertionsDisabledClassCache = makeEmptyClass(STATIC | SYNTHETIC, outermostClassDef.sym).sym;
1949
1950        return assertionsDisabledClassCache;
1951    }
1952
1953    // This code is not particularly robust if the user has
1954    // previously declared a member named '$assertionsDisabled'.
1955    // The same faulty idiom also appears in the translation of
1956    // class literals above.  We should report an error if a
1957    // previous declaration is not synthetic.
1958
1959    private JCExpression assertFlagTest(DiagnosticPosition pos) {
1960        // Outermost class may be either true class or an interface.
1961        ClassSymbol outermostClass = outermostClassDef.sym;
1962
1963        //only classes can hold a non-public field, look for a usable one:
1964        ClassSymbol container = !currentClass.isInterface() ? currentClass :
1965                assertionsDisabledClass();
1966
1967        VarSymbol assertDisabledSym =
1968            (VarSymbol)lookupSynthetic(dollarAssertionsDisabled,
1969                                       container.members());
1970        if (assertDisabledSym == null) {
1971            assertDisabledSym =
1972                new VarSymbol(STATIC | FINAL | SYNTHETIC,
1973                              dollarAssertionsDisabled,
1974                              syms.booleanType,
1975                              container);
1976            enterSynthetic(pos, assertDisabledSym, container.members());
1977            Symbol desiredAssertionStatusSym = lookupMethod(pos,
1978                                                            names.desiredAssertionStatus,
1979                                                            types.erasure(syms.classType),
1980                                                            List.nil());
1981            JCClassDecl containerDef = classDef(container);
1982            make_at(containerDef.pos());
1983            JCExpression notStatus = makeUnary(NOT, make.App(make.Select(
1984                    classOfType(types.erasure(outermostClass.type),
1985                                containerDef.pos()),
1986                    desiredAssertionStatusSym)));
1987            JCVariableDecl assertDisabledDef = make.VarDef(assertDisabledSym,
1988                                                   notStatus);
1989            containerDef.defs = containerDef.defs.prepend(assertDisabledDef);
1990
1991            if (currentClass.isInterface()) {
1992                //need to load the assertions enabled/disabled state while
1993                //initializing the interface:
1994                JCClassDecl currentClassDef = classDef(currentClass);
1995                make_at(currentClassDef.pos());
1996                JCStatement dummy = make.If(make.QualIdent(assertDisabledSym), make.Skip(), null);
1997                JCBlock clinit = make.Block(STATIC, List.of(dummy));
1998                currentClassDef.defs = currentClassDef.defs.prepend(clinit);
1999            }
2000        }
2001        make_at(pos);
2002        return makeUnary(NOT, make.Ident(assertDisabledSym));
2003    }
2004
2005
2006/**************************************************************************
2007 * Building blocks for let expressions
2008 *************************************************************************/
2009
2010    interface TreeBuilder {
2011        JCExpression build(JCExpression arg);
2012    }
2013
2014    /** Construct an expression using the builder, with the given rval
2015     *  expression as an argument to the builder.  However, the rval
2016     *  expression must be computed only once, even if used multiple
2017     *  times in the result of the builder.  We do that by
2018     *  constructing a "let" expression that saves the rvalue into a
2019     *  temporary variable and then uses the temporary variable in
2020     *  place of the expression built by the builder.  The complete
2021     *  resulting expression is of the form
2022     *  <pre>
2023     *    (let <b>TYPE</b> <b>TEMP</b> = <b>RVAL</b>;
2024     *     in (<b>BUILDER</b>(<b>TEMP</b>)))
2025     *  </pre>
2026     *  where <code><b>TEMP</b></code> is a newly declared variable
2027     *  in the let expression.
2028     */
2029    JCExpression abstractRval(JCExpression rval, Type type, TreeBuilder builder) {
2030        rval = TreeInfo.skipParens(rval);
2031        switch (rval.getTag()) {
2032        case LITERAL:
2033            return builder.build(rval);
2034        case IDENT:
2035            JCIdent id = (JCIdent) rval;
2036            if ((id.sym.flags() & FINAL) != 0 && id.sym.owner.kind == MTH)
2037                return builder.build(rval);
2038        }
2039        Name name = TreeInfo.name(rval);
2040        if (name == names._super || name == names._this)
2041            return builder.build(rval);
2042        VarSymbol var =
2043            new VarSymbol(FINAL|SYNTHETIC,
2044                          names.fromString(
2045                                          target.syntheticNameChar()
2046                                          + "" + rval.hashCode()),
2047                                      type,
2048                                      currentMethodSym);
2049        rval = convert(rval,type);
2050        JCVariableDecl def = make.VarDef(var, rval); // XXX cast
2051        JCExpression built = builder.build(make.Ident(var));
2052        JCExpression res = make.LetExpr(def, built);
2053        res.type = built.type;
2054        return res;
2055    }
2056
2057    // same as above, with the type of the temporary variable computed
2058    JCExpression abstractRval(JCExpression rval, TreeBuilder builder) {
2059        return abstractRval(rval, rval.type, builder);
2060    }
2061
2062    // same as above, but for an expression that may be used as either
2063    // an rvalue or an lvalue.  This requires special handling for
2064    // Select expressions, where we place the left-hand-side of the
2065    // select in a temporary, and for Indexed expressions, where we
2066    // place both the indexed expression and the index value in temps.
2067    JCExpression abstractLval(JCExpression lval, final TreeBuilder builder) {
2068        lval = TreeInfo.skipParens(lval);
2069        switch (lval.getTag()) {
2070        case IDENT:
2071            return builder.build(lval);
2072        case SELECT: {
2073            final JCFieldAccess s = (JCFieldAccess)lval;
2074            Symbol lid = TreeInfo.symbol(s.selected);
2075            if (lid != null && lid.kind == TYP) return builder.build(lval);
2076            return abstractRval(s.selected, selected -> builder.build(make.Select(selected, s.sym)));
2077        }
2078        case INDEXED: {
2079            final JCArrayAccess i = (JCArrayAccess)lval;
2080            return abstractRval(i.indexed, indexed -> abstractRval(i.index, syms.intType, index -> {
2081                JCExpression newLval = make.Indexed(indexed, index);
2082                newLval.setType(i.type);
2083                return builder.build(newLval);
2084            }));
2085        }
2086        case TYPECAST: {
2087            return abstractLval(((JCTypeCast)lval).expr, builder);
2088        }
2089        }
2090        throw new AssertionError(lval);
2091    }
2092
2093    // evaluate and discard the first expression, then evaluate the second.
2094    JCExpression makeComma(final JCExpression expr1, final JCExpression expr2) {
2095        return abstractRval(expr1, discarded -> expr2);
2096    }
2097
2098/**************************************************************************
2099 * Translation methods
2100 *************************************************************************/
2101
2102    /** Visitor argument: enclosing operator node.
2103     */
2104    private JCExpression enclOp;
2105
2106    /** Visitor method: Translate a single node.
2107     *  Attach the source position from the old tree to its replacement tree.
2108     */
2109    @Override
2110    public <T extends JCTree> T translate(T tree) {
2111        if (tree == null) {
2112            return null;
2113        } else {
2114            make_at(tree.pos());
2115            T result = super.translate(tree);
2116            if (endPosTable != null && result != tree) {
2117                endPosTable.replaceTree(tree, result);
2118            }
2119            return result;
2120        }
2121    }
2122
2123    /** Visitor method: Translate a single node, boxing or unboxing if needed.
2124     */
2125    public <T extends JCExpression> T translate(T tree, Type type) {
2126        return (tree == null) ? null : boxIfNeeded(translate(tree), type);
2127    }
2128
2129    /** Visitor method: Translate tree.
2130     */
2131    public <T extends JCTree> T translate(T tree, JCExpression enclOp) {
2132        JCExpression prevEnclOp = this.enclOp;
2133        this.enclOp = enclOp;
2134        T res = translate(tree);
2135        this.enclOp = prevEnclOp;
2136        return res;
2137    }
2138
2139    /** Visitor method: Translate list of trees.
2140     */
2141    public <T extends JCExpression> List<T> translate(List<T> trees, Type type) {
2142        if (trees == null) return null;
2143        for (List<T> l = trees; l.nonEmpty(); l = l.tail)
2144            l.head = translate(l.head, type);
2145        return trees;
2146    }
2147
2148    public void visitPackageDef(JCPackageDecl tree) {
2149        if (!needPackageInfoClass(tree))
2150                        return;
2151
2152        long flags = Flags.ABSTRACT | Flags.INTERFACE;
2153        // package-info is marked SYNTHETIC in JDK 1.6 and later releases
2154        flags = flags | Flags.SYNTHETIC;
2155        ClassSymbol c = tree.packge.package_info;
2156        c.setAttributes(tree.packge);
2157        c.flags_field |= flags;
2158        ClassType ctype = (ClassType) c.type;
2159        ctype.supertype_field = syms.objectType;
2160        ctype.interfaces_field = List.nil();
2161        createInfoClass(tree.annotations, c);
2162    }
2163    // where
2164    private boolean needPackageInfoClass(JCPackageDecl pd) {
2165        switch (pkginfoOpt) {
2166            case ALWAYS:
2167                return true;
2168            case LEGACY:
2169                return pd.getAnnotations().nonEmpty();
2170            case NONEMPTY:
2171                for (Attribute.Compound a :
2172                         pd.packge.getDeclarationAttributes()) {
2173                    Attribute.RetentionPolicy p = types.getRetention(a);
2174                    if (p != Attribute.RetentionPolicy.SOURCE)
2175                        return true;
2176                }
2177                return false;
2178        }
2179        throw new AssertionError();
2180    }
2181
2182    public void visitModuleDef(JCModuleDecl tree) {
2183        ModuleSymbol msym = tree.sym;
2184        ClassSymbol c = msym.module_info;
2185        c.setAttributes(msym);
2186        c.flags_field |= Flags.MODULE;
2187        createInfoClass(List.nil(), tree.sym.module_info);
2188    }
2189
2190    private void createInfoClass(List<JCAnnotation> annots, ClassSymbol c) {
2191        long flags = Flags.ABSTRACT | Flags.INTERFACE;
2192        JCClassDecl infoClass =
2193                make.ClassDef(make.Modifiers(flags, annots),
2194                    c.name, List.nil(),
2195                    null, List.nil(), List.nil());
2196        infoClass.sym = c;
2197        translated.append(infoClass);
2198    }
2199
2200    public void visitClassDef(JCClassDecl tree) {
2201        Env<AttrContext> prevEnv = attrEnv;
2202        ClassSymbol currentClassPrev = currentClass;
2203        MethodSymbol currentMethodSymPrev = currentMethodSym;
2204
2205        currentClass = tree.sym;
2206        currentMethodSym = null;
2207        attrEnv = typeEnvs.remove(currentClass);
2208        if (attrEnv == null)
2209            attrEnv = prevEnv;
2210
2211        classdefs.put(currentClass, tree);
2212
2213        proxies = proxies.dup(currentClass);
2214        List<VarSymbol> prevOuterThisStack = outerThisStack;
2215
2216        // If this is an enum definition
2217        if ((tree.mods.flags & ENUM) != 0 &&
2218            (types.supertype(currentClass.type).tsym.flags() & ENUM) == 0)
2219            visitEnumDef(tree);
2220
2221        // If this is a nested class, define a this$n field for
2222        // it and add to proxies.
2223        JCVariableDecl otdef = null;
2224        if (currentClass.hasOuterInstance())
2225            otdef = outerThisDef(tree.pos, currentClass);
2226
2227        // If this is a local class, define proxies for all its free variables.
2228        List<JCVariableDecl> fvdefs = freevarDefs(
2229            tree.pos, freevars(currentClass), currentClass);
2230
2231        // Recursively translate superclass, interfaces.
2232        tree.extending = translate(tree.extending);
2233        tree.implementing = translate(tree.implementing);
2234
2235        if (currentClass.isLocal()) {
2236            ClassSymbol encl = currentClass.owner.enclClass();
2237            if (encl.trans_local == null) {
2238                encl.trans_local = List.nil();
2239            }
2240            encl.trans_local = encl.trans_local.prepend(currentClass);
2241        }
2242
2243        // Recursively translate members, taking into account that new members
2244        // might be created during the translation and prepended to the member
2245        // list `tree.defs'.
2246        List<JCTree> seen = List.nil();
2247        while (tree.defs != seen) {
2248            List<JCTree> unseen = tree.defs;
2249            for (List<JCTree> l = unseen; l.nonEmpty() && l != seen; l = l.tail) {
2250                JCTree outermostMemberDefPrev = outermostMemberDef;
2251                if (outermostMemberDefPrev == null) outermostMemberDef = l.head;
2252                l.head = translate(l.head);
2253                outermostMemberDef = outermostMemberDefPrev;
2254            }
2255            seen = unseen;
2256        }
2257
2258        // Convert a protected modifier to public, mask static modifier.
2259        if ((tree.mods.flags & PROTECTED) != 0) tree.mods.flags |= PUBLIC;
2260        tree.mods.flags &= ClassFlags;
2261
2262        // Convert name to flat representation, replacing '.' by '$'.
2263        tree.name = Convert.shortName(currentClass.flatName());
2264
2265        // Add this$n and free variables proxy definitions to class.
2266
2267        for (List<JCVariableDecl> l = fvdefs; l.nonEmpty(); l = l.tail) {
2268            tree.defs = tree.defs.prepend(l.head);
2269            enterSynthetic(tree.pos(), l.head.sym, currentClass.members());
2270        }
2271        if (currentClass.hasOuterInstance()) {
2272            tree.defs = tree.defs.prepend(otdef);
2273            enterSynthetic(tree.pos(), otdef.sym, currentClass.members());
2274        }
2275
2276        proxies = proxies.leave();
2277        outerThisStack = prevOuterThisStack;
2278
2279        // Append translated tree to `translated' queue.
2280        translated.append(tree);
2281
2282        attrEnv = prevEnv;
2283        currentClass = currentClassPrev;
2284        currentMethodSym = currentMethodSymPrev;
2285
2286        // Return empty block {} as a placeholder for an inner class.
2287        result = make_at(tree.pos()).Block(SYNTHETIC, List.nil());
2288    }
2289
2290    /** Translate an enum class. */
2291    private void visitEnumDef(JCClassDecl tree) {
2292        make_at(tree.pos());
2293
2294        // add the supertype, if needed
2295        if (tree.extending == null)
2296            tree.extending = make.Type(types.supertype(tree.type));
2297
2298        // classOfType adds a cache field to tree.defs
2299        JCExpression e_class = classOfType(tree.sym.type, tree.pos()).
2300            setType(types.erasure(syms.classType));
2301
2302        // process each enumeration constant, adding implicit constructor parameters
2303        int nextOrdinal = 0;
2304        ListBuffer<JCExpression> values = new ListBuffer<>();
2305        ListBuffer<JCTree> enumDefs = new ListBuffer<>();
2306        ListBuffer<JCTree> otherDefs = new ListBuffer<>();
2307        for (List<JCTree> defs = tree.defs;
2308             defs.nonEmpty();
2309             defs=defs.tail) {
2310            if (defs.head.hasTag(VARDEF) && (((JCVariableDecl) defs.head).mods.flags & ENUM) != 0) {
2311                JCVariableDecl var = (JCVariableDecl)defs.head;
2312                visitEnumConstantDef(var, nextOrdinal++);
2313                values.append(make.QualIdent(var.sym));
2314                enumDefs.append(var);
2315            } else {
2316                otherDefs.append(defs.head);
2317            }
2318        }
2319
2320        // private static final T[] #VALUES = { a, b, c };
2321        Name valuesName = names.fromString(target.syntheticNameChar() + "VALUES");
2322        while (tree.sym.members().findFirst(valuesName) != null) // avoid name clash
2323            valuesName = names.fromString(valuesName + "" + target.syntheticNameChar());
2324        Type arrayType = new ArrayType(types.erasure(tree.type), syms.arrayClass);
2325        VarSymbol valuesVar = new VarSymbol(PRIVATE|FINAL|STATIC|SYNTHETIC,
2326                                            valuesName,
2327                                            arrayType,
2328                                            tree.type.tsym);
2329        JCNewArray newArray = make.NewArray(make.Type(types.erasure(tree.type)),
2330                                          List.nil(),
2331                                          values.toList());
2332        newArray.type = arrayType;
2333        enumDefs.append(make.VarDef(valuesVar, newArray));
2334        tree.sym.members().enter(valuesVar);
2335
2336        Symbol valuesSym = lookupMethod(tree.pos(), names.values,
2337                                        tree.type, List.nil());
2338        List<JCStatement> valuesBody;
2339        if (useClone()) {
2340            // return (T[]) $VALUES.clone();
2341            JCTypeCast valuesResult =
2342                make.TypeCast(valuesSym.type.getReturnType(),
2343                              make.App(make.Select(make.Ident(valuesVar),
2344                                                   syms.arrayCloneMethod)));
2345            valuesBody = List.of(make.Return(valuesResult));
2346        } else {
2347            // template: T[] $result = new T[$values.length];
2348            Name resultName = names.fromString(target.syntheticNameChar() + "result");
2349            while (tree.sym.members().findFirst(resultName) != null) // avoid name clash
2350                resultName = names.fromString(resultName + "" + target.syntheticNameChar());
2351            VarSymbol resultVar = new VarSymbol(FINAL|SYNTHETIC,
2352                                                resultName,
2353                                                arrayType,
2354                                                valuesSym);
2355            JCNewArray resultArray = make.NewArray(make.Type(types.erasure(tree.type)),
2356                                  List.of(make.Select(make.Ident(valuesVar), syms.lengthVar)),
2357                                  null);
2358            resultArray.type = arrayType;
2359            JCVariableDecl decl = make.VarDef(resultVar, resultArray);
2360
2361            // template: System.arraycopy($VALUES, 0, $result, 0, $VALUES.length);
2362            if (systemArraycopyMethod == null) {
2363                systemArraycopyMethod =
2364                    new MethodSymbol(PUBLIC | STATIC,
2365                                     names.fromString("arraycopy"),
2366                                     new MethodType(List.of(syms.objectType,
2367                                                            syms.intType,
2368                                                            syms.objectType,
2369                                                            syms.intType,
2370                                                            syms.intType),
2371                                                    syms.voidType,
2372                                                    List.nil(),
2373                                                    syms.methodClass),
2374                                     syms.systemType.tsym);
2375            }
2376            JCStatement copy =
2377                make.Exec(make.App(make.Select(make.Ident(syms.systemType.tsym),
2378                                               systemArraycopyMethod),
2379                          List.of(make.Ident(valuesVar), make.Literal(0),
2380                                  make.Ident(resultVar), make.Literal(0),
2381                                  make.Select(make.Ident(valuesVar), syms.lengthVar))));
2382
2383            // template: return $result;
2384            JCStatement ret = make.Return(make.Ident(resultVar));
2385            valuesBody = List.of(decl, copy, ret);
2386        }
2387
2388        JCMethodDecl valuesDef =
2389             make.MethodDef((MethodSymbol)valuesSym, make.Block(0, valuesBody));
2390
2391        enumDefs.append(valuesDef);
2392
2393        if (debugLower)
2394            System.err.println(tree.sym + ".valuesDef = " + valuesDef);
2395
2396        /** The template for the following code is:
2397         *
2398         *     public static E valueOf(String name) {
2399         *         return (E)Enum.valueOf(E.class, name);
2400         *     }
2401         *
2402         *  where E is tree.sym
2403         */
2404        MethodSymbol valueOfSym = lookupMethod(tree.pos(),
2405                         names.valueOf,
2406                         tree.sym.type,
2407                         List.of(syms.stringType));
2408        Assert.check((valueOfSym.flags() & STATIC) != 0);
2409        VarSymbol nameArgSym = valueOfSym.params.head;
2410        JCIdent nameVal = make.Ident(nameArgSym);
2411        JCStatement enum_ValueOf =
2412            make.Return(make.TypeCast(tree.sym.type,
2413                                      makeCall(make.Ident(syms.enumSym),
2414                                               names.valueOf,
2415                                               List.of(e_class, nameVal))));
2416        JCMethodDecl valueOf = make.MethodDef(valueOfSym,
2417                                           make.Block(0, List.of(enum_ValueOf)));
2418        nameVal.sym = valueOf.params.head.sym;
2419        if (debugLower)
2420            System.err.println(tree.sym + ".valueOf = " + valueOf);
2421        enumDefs.append(valueOf);
2422
2423        enumDefs.appendList(otherDefs.toList());
2424        tree.defs = enumDefs.toList();
2425    }
2426        // where
2427        private MethodSymbol systemArraycopyMethod;
2428        private boolean useClone() {
2429            try {
2430                return syms.objectType.tsym.members().findFirst(names.clone) != null;
2431            }
2432            catch (CompletionFailure e) {
2433                return false;
2434            }
2435        }
2436
2437    /** Translate an enumeration constant and its initializer. */
2438    private void visitEnumConstantDef(JCVariableDecl var, int ordinal) {
2439        JCNewClass varDef = (JCNewClass)var.init;
2440        varDef.args = varDef.args.
2441            prepend(makeLit(syms.intType, ordinal)).
2442            prepend(makeLit(syms.stringType, var.name.toString()));
2443    }
2444
2445    public void visitMethodDef(JCMethodDecl tree) {
2446        if (tree.name == names.init && (currentClass.flags_field&ENUM) != 0) {
2447            // Add "String $enum$name, int $enum$ordinal" to the beginning of the
2448            // argument list for each constructor of an enum.
2449            JCVariableDecl nameParam = make_at(tree.pos()).
2450                Param(names.fromString(target.syntheticNameChar() +
2451                                       "enum" + target.syntheticNameChar() + "name"),
2452                      syms.stringType, tree.sym);
2453            nameParam.mods.flags |= SYNTHETIC; nameParam.sym.flags_field |= SYNTHETIC;
2454            JCVariableDecl ordParam = make.
2455                Param(names.fromString(target.syntheticNameChar() +
2456                                       "enum" + target.syntheticNameChar() +
2457                                       "ordinal"),
2458                      syms.intType, tree.sym);
2459            ordParam.mods.flags |= SYNTHETIC; ordParam.sym.flags_field |= SYNTHETIC;
2460
2461            MethodSymbol m = tree.sym;
2462            tree.params = tree.params.prepend(ordParam).prepend(nameParam);
2463
2464            m.extraParams = m.extraParams.prepend(ordParam.sym);
2465            m.extraParams = m.extraParams.prepend(nameParam.sym);
2466            Type olderasure = m.erasure(types);
2467            m.erasure_field = new MethodType(
2468                olderasure.getParameterTypes().prepend(syms.intType).prepend(syms.stringType),
2469                olderasure.getReturnType(),
2470                olderasure.getThrownTypes(),
2471                syms.methodClass);
2472        }
2473
2474        JCMethodDecl prevMethodDef = currentMethodDef;
2475        MethodSymbol prevMethodSym = currentMethodSym;
2476        try {
2477            currentMethodDef = tree;
2478            currentMethodSym = tree.sym;
2479            visitMethodDefInternal(tree);
2480        } finally {
2481            currentMethodDef = prevMethodDef;
2482            currentMethodSym = prevMethodSym;
2483        }
2484    }
2485
2486    private void visitMethodDefInternal(JCMethodDecl tree) {
2487        if (tree.name == names.init &&
2488            (currentClass.isInner() || currentClass.isLocal())) {
2489            // We are seeing a constructor of an inner class.
2490            MethodSymbol m = tree.sym;
2491
2492            // Push a new proxy scope for constructor parameters.
2493            // and create definitions for any this$n and proxy parameters.
2494            proxies = proxies.dup(m);
2495            List<VarSymbol> prevOuterThisStack = outerThisStack;
2496            List<VarSymbol> fvs = freevars(currentClass);
2497            JCVariableDecl otdef = null;
2498            if (currentClass.hasOuterInstance())
2499                otdef = outerThisDef(tree.pos, m);
2500            List<JCVariableDecl> fvdefs = freevarDefs(tree.pos, fvs, m, PARAMETER);
2501
2502            // Recursively translate result type, parameters and thrown list.
2503            tree.restype = translate(tree.restype);
2504            tree.params = translateVarDefs(tree.params);
2505            tree.thrown = translate(tree.thrown);
2506
2507            // when compiling stubs, don't process body
2508            if (tree.body == null) {
2509                result = tree;
2510                return;
2511            }
2512
2513            // Add this$n (if needed) in front of and free variables behind
2514            // constructor parameter list.
2515            tree.params = tree.params.appendList(fvdefs);
2516            if (currentClass.hasOuterInstance()) {
2517                tree.params = tree.params.prepend(otdef);
2518            }
2519
2520            // If this is an initial constructor, i.e., it does not start with
2521            // this(...), insert initializers for this$n and proxies
2522            // before (pre-1.4, after) the call to superclass constructor.
2523            JCStatement selfCall = translate(tree.body.stats.head);
2524
2525            List<JCStatement> added = List.nil();
2526            if (fvs.nonEmpty()) {
2527                List<Type> addedargtypes = List.nil();
2528                for (List<VarSymbol> l = fvs; l.nonEmpty(); l = l.tail) {
2529                    final Name pName = proxyName(l.head.name);
2530                    m.capturedLocals =
2531                        m.capturedLocals.prepend((VarSymbol)
2532                                                (proxies.findFirst(pName)));
2533                    if (TreeInfo.isInitialConstructor(tree)) {
2534                        added = added.prepend(
2535                          initField(tree.body.pos, pName));
2536                    }
2537                    addedargtypes = addedargtypes.prepend(l.head.erasure(types));
2538                }
2539                Type olderasure = m.erasure(types);
2540                m.erasure_field = new MethodType(
2541                    olderasure.getParameterTypes().appendList(addedargtypes),
2542                    olderasure.getReturnType(),
2543                    olderasure.getThrownTypes(),
2544                    syms.methodClass);
2545            }
2546            if (currentClass.hasOuterInstance() &&
2547                TreeInfo.isInitialConstructor(tree))
2548            {
2549                added = added.prepend(initOuterThis(tree.body.pos));
2550            }
2551
2552            // pop local variables from proxy stack
2553            proxies = proxies.leave();
2554
2555            // recursively translate following local statements and
2556            // combine with this- or super-call
2557            List<JCStatement> stats = translate(tree.body.stats.tail);
2558            tree.body.stats = stats.prepend(selfCall).prependList(added);
2559            outerThisStack = prevOuterThisStack;
2560        } else {
2561            Map<Symbol, Symbol> prevLambdaTranslationMap =
2562                    lambdaTranslationMap;
2563            try {
2564                lambdaTranslationMap = (tree.sym.flags() & SYNTHETIC) != 0 &&
2565                        tree.sym.name.startsWith(names.lambda) ?
2566                        makeTranslationMap(tree) : null;
2567                super.visitMethodDef(tree);
2568            } finally {
2569                lambdaTranslationMap = prevLambdaTranslationMap;
2570            }
2571        }
2572        result = tree;
2573    }
2574    //where
2575        private Map<Symbol, Symbol> makeTranslationMap(JCMethodDecl tree) {
2576            Map<Symbol, Symbol> translationMap = new HashMap<>();
2577            for (JCVariableDecl vd : tree.params) {
2578                Symbol p = vd.sym;
2579                if (p != p.baseSymbol()) {
2580                    translationMap.put(p.baseSymbol(), p);
2581                }
2582            }
2583            return translationMap;
2584        }
2585
2586    public void visitTypeCast(JCTypeCast tree) {
2587        tree.clazz = translate(tree.clazz);
2588        if (tree.type.isPrimitive() != tree.expr.type.isPrimitive())
2589            tree.expr = translate(tree.expr, tree.type);
2590        else
2591            tree.expr = translate(tree.expr);
2592        result = tree;
2593    }
2594
2595    public void visitNewClass(JCNewClass tree) {
2596        ClassSymbol c = (ClassSymbol)tree.constructor.owner;
2597
2598        // Box arguments, if necessary
2599        boolean isEnum = (tree.constructor.owner.flags() & ENUM) != 0;
2600        List<Type> argTypes = tree.constructor.type.getParameterTypes();
2601        if (isEnum) argTypes = argTypes.prepend(syms.intType).prepend(syms.stringType);
2602        tree.args = boxArgs(argTypes, tree.args, tree.varargsElement);
2603        tree.varargsElement = null;
2604
2605        // If created class is local, add free variables after
2606        // explicit constructor arguments.
2607        if (c.isLocal()) {
2608            tree.args = tree.args.appendList(loadFreevars(tree.pos(), freevars(c)));
2609        }
2610
2611        // If an access constructor is used, append null as a last argument.
2612        Symbol constructor = accessConstructor(tree.pos(), tree.constructor);
2613        if (constructor != tree.constructor) {
2614            tree.args = tree.args.append(makeNull());
2615            tree.constructor = constructor;
2616        }
2617
2618        // If created class has an outer instance, and new is qualified, pass
2619        // qualifier as first argument. If new is not qualified, pass the
2620        // correct outer instance as first argument.
2621        if (c.hasOuterInstance()) {
2622            JCExpression thisArg;
2623            if (tree.encl != null) {
2624                thisArg = attr.makeNullCheck(translate(tree.encl));
2625                thisArg.type = tree.encl.type;
2626            } else if (c.isLocal()) {
2627                // local class
2628                thisArg = makeThis(tree.pos(), c.type.getEnclosingType().tsym);
2629            } else {
2630                // nested class
2631                thisArg = makeOwnerThis(tree.pos(), c, false);
2632            }
2633            tree.args = tree.args.prepend(thisArg);
2634        }
2635        tree.encl = null;
2636
2637        // If we have an anonymous class, create its flat version, rather
2638        // than the class or interface following new.
2639        if (tree.def != null) {
2640            translate(tree.def);
2641            tree.clazz = access(make_at(tree.clazz.pos()).Ident(tree.def.sym));
2642            tree.def = null;
2643        } else {
2644            tree.clazz = access(c, tree.clazz, enclOp, false);
2645        }
2646        result = tree;
2647    }
2648
2649    // Simplify conditionals with known constant controlling expressions.
2650    // This allows us to avoid generating supporting declarations for
2651    // the dead code, which will not be eliminated during code generation.
2652    // Note that Flow.isFalse and Flow.isTrue only return true
2653    // for constant expressions in the sense of JLS 15.27, which
2654    // are guaranteed to have no side-effects.  More aggressive
2655    // constant propagation would require that we take care to
2656    // preserve possible side-effects in the condition expression.
2657
2658    // One common case is equality expressions involving a constant and null.
2659    // Since null is not a constant expression (because null cannot be
2660    // represented in the constant pool), equality checks involving null are
2661    // not captured by Flow.isTrue/isFalse.
2662    // Equality checks involving a constant and null, e.g.
2663    //     "" == null
2664    // are safe to simplify as no side-effects can occur.
2665
2666    private boolean isTrue(JCTree exp) {
2667        if (exp.type.isTrue())
2668            return true;
2669        Boolean b = expValue(exp);
2670        return b == null ? false : b;
2671    }
2672    private boolean isFalse(JCTree exp) {
2673        if (exp.type.isFalse())
2674            return true;
2675        Boolean b = expValue(exp);
2676        return b == null ? false : !b;
2677    }
2678    /* look for (in)equality relations involving null.
2679     * return true - if expression is always true
2680     *       false - if expression is always false
2681     *        null - if expression cannot be eliminated
2682     */
2683    private Boolean expValue(JCTree exp) {
2684        while (exp.hasTag(PARENS))
2685            exp = ((JCParens)exp).expr;
2686
2687        boolean eq;
2688        switch (exp.getTag()) {
2689        case EQ: eq = true;  break;
2690        case NE: eq = false; break;
2691        default:
2692            return null;
2693        }
2694
2695        // we have a JCBinary(EQ|NE)
2696        // check if we have two literals (constants or null)
2697        JCBinary b = (JCBinary)exp;
2698        if (b.lhs.type.hasTag(BOT)) return expValueIsNull(eq, b.rhs);
2699        if (b.rhs.type.hasTag(BOT)) return expValueIsNull(eq, b.lhs);
2700        return null;
2701    }
2702    private Boolean expValueIsNull(boolean eq, JCTree t) {
2703        if (t.type.hasTag(BOT)) return Boolean.valueOf(eq);
2704        if (t.hasTag(LITERAL))  return Boolean.valueOf(!eq);
2705        return null;
2706    }
2707
2708    /** Visitor method for conditional expressions.
2709     */
2710    @Override
2711    public void visitConditional(JCConditional tree) {
2712        JCTree cond = tree.cond = translate(tree.cond, syms.booleanType);
2713        if (isTrue(cond)) {
2714            result = convert(translate(tree.truepart, tree.type), tree.type);
2715            addPrunedInfo(cond);
2716        } else if (isFalse(cond)) {
2717            result = convert(translate(tree.falsepart, tree.type), tree.type);
2718            addPrunedInfo(cond);
2719        } else {
2720            // Condition is not a compile-time constant.
2721            tree.truepart = translate(tree.truepart, tree.type);
2722            tree.falsepart = translate(tree.falsepart, tree.type);
2723            result = tree;
2724        }
2725    }
2726//where
2727    private JCExpression convert(JCExpression tree, Type pt) {
2728        if (tree.type == pt || tree.type.hasTag(BOT))
2729            return tree;
2730        JCExpression result = make_at(tree.pos()).TypeCast(make.Type(pt), tree);
2731        result.type = (tree.type.constValue() != null) ? cfolder.coerce(tree.type, pt)
2732                                                       : pt;
2733        return result;
2734    }
2735
2736    /** Visitor method for if statements.
2737     */
2738    public void visitIf(JCIf tree) {
2739        JCTree cond = tree.cond = translate(tree.cond, syms.booleanType);
2740        if (isTrue(cond)) {
2741            result = translate(tree.thenpart);
2742            addPrunedInfo(cond);
2743        } else if (isFalse(cond)) {
2744            if (tree.elsepart != null) {
2745                result = translate(tree.elsepart);
2746            } else {
2747                result = make.Skip();
2748            }
2749            addPrunedInfo(cond);
2750        } else {
2751            // Condition is not a compile-time constant.
2752            tree.thenpart = translate(tree.thenpart);
2753            tree.elsepart = translate(tree.elsepart);
2754            result = tree;
2755        }
2756    }
2757
2758    /** Visitor method for assert statements. Translate them away.
2759     */
2760    public void visitAssert(JCAssert tree) {
2761        tree.cond = translate(tree.cond, syms.booleanType);
2762        if (!tree.cond.type.isTrue()) {
2763            JCExpression cond = assertFlagTest(tree.pos());
2764            List<JCExpression> exnArgs = (tree.detail == null) ?
2765                List.nil() : List.of(translate(tree.detail));
2766            if (!tree.cond.type.isFalse()) {
2767                cond = makeBinary
2768                    (AND,
2769                     cond,
2770                     makeUnary(NOT, tree.cond));
2771            }
2772            result =
2773                make.If(cond,
2774                        make_at(tree).
2775                           Throw(makeNewClass(syms.assertionErrorType, exnArgs)),
2776                        null);
2777        } else {
2778            result = make.Skip();
2779        }
2780    }
2781
2782    public void visitApply(JCMethodInvocation tree) {
2783        Symbol meth = TreeInfo.symbol(tree.meth);
2784        List<Type> argtypes = meth.type.getParameterTypes();
2785        if (meth.name == names.init && meth.owner == syms.enumSym)
2786            argtypes = argtypes.tail.tail;
2787        tree.args = boxArgs(argtypes, tree.args, tree.varargsElement);
2788        tree.varargsElement = null;
2789        Name methName = TreeInfo.name(tree.meth);
2790        if (meth.name==names.init) {
2791            // We are seeing a this(...) or super(...) constructor call.
2792            // If an access constructor is used, append null as a last argument.
2793            Symbol constructor = accessConstructor(tree.pos(), meth);
2794            if (constructor != meth) {
2795                tree.args = tree.args.append(makeNull());
2796                TreeInfo.setSymbol(tree.meth, constructor);
2797            }
2798
2799            // If we are calling a constructor of a local class, add
2800            // free variables after explicit constructor arguments.
2801            ClassSymbol c = (ClassSymbol)constructor.owner;
2802            if (c.isLocal()) {
2803                tree.args = tree.args.appendList(loadFreevars(tree.pos(), freevars(c)));
2804            }
2805
2806            // If we are calling a constructor of an enum class, pass
2807            // along the name and ordinal arguments
2808            if ((c.flags_field&ENUM) != 0 || c.getQualifiedName() == names.java_lang_Enum) {
2809                List<JCVariableDecl> params = currentMethodDef.params;
2810                if (currentMethodSym.owner.hasOuterInstance())
2811                    params = params.tail; // drop this$n
2812                tree.args = tree.args
2813                    .prepend(make_at(tree.pos()).Ident(params.tail.head.sym)) // ordinal
2814                    .prepend(make.Ident(params.head.sym)); // name
2815            }
2816
2817            // If we are calling a constructor of a class with an outer
2818            // instance, and the call
2819            // is qualified, pass qualifier as first argument in front of
2820            // the explicit constructor arguments. If the call
2821            // is not qualified, pass the correct outer instance as
2822            // first argument.
2823            if (c.hasOuterInstance()) {
2824                JCExpression thisArg;
2825                if (tree.meth.hasTag(SELECT)) {
2826                    thisArg = attr.
2827                        makeNullCheck(translate(((JCFieldAccess) tree.meth).selected));
2828                    tree.meth = make.Ident(constructor);
2829                    ((JCIdent) tree.meth).name = methName;
2830                } else if (c.isLocal() || methName == names._this){
2831                    // local class or this() call
2832                    thisArg = makeThis(tree.meth.pos(), c.type.getEnclosingType().tsym);
2833                } else {
2834                    // super() call of nested class - never pick 'this'
2835                    thisArg = makeOwnerThisN(tree.meth.pos(), c, false);
2836                }
2837                tree.args = tree.args.prepend(thisArg);
2838            }
2839        } else {
2840            // We are seeing a normal method invocation; translate this as usual.
2841            tree.meth = translate(tree.meth);
2842
2843            // If the translated method itself is an Apply tree, we are
2844            // seeing an access method invocation. In this case, append
2845            // the method arguments to the arguments of the access method.
2846            if (tree.meth.hasTag(APPLY)) {
2847                JCMethodInvocation app = (JCMethodInvocation)tree.meth;
2848                app.args = tree.args.prependList(app.args);
2849                result = app;
2850                return;
2851            }
2852        }
2853        result = tree;
2854    }
2855
2856    List<JCExpression> boxArgs(List<Type> parameters, List<JCExpression> _args, Type varargsElement) {
2857        List<JCExpression> args = _args;
2858        if (parameters.isEmpty()) return args;
2859        boolean anyChanges = false;
2860        ListBuffer<JCExpression> result = new ListBuffer<>();
2861        while (parameters.tail.nonEmpty()) {
2862            JCExpression arg = translate(args.head, parameters.head);
2863            anyChanges |= (arg != args.head);
2864            result.append(arg);
2865            args = args.tail;
2866            parameters = parameters.tail;
2867        }
2868        Type parameter = parameters.head;
2869        if (varargsElement != null) {
2870            anyChanges = true;
2871            ListBuffer<JCExpression> elems = new ListBuffer<>();
2872            while (args.nonEmpty()) {
2873                JCExpression arg = translate(args.head, varargsElement);
2874                elems.append(arg);
2875                args = args.tail;
2876            }
2877            JCNewArray boxedArgs = make.NewArray(make.Type(varargsElement),
2878                                               List.nil(),
2879                                               elems.toList());
2880            boxedArgs.type = new ArrayType(varargsElement, syms.arrayClass);
2881            result.append(boxedArgs);
2882        } else {
2883            if (args.length() != 1) throw new AssertionError(args);
2884            JCExpression arg = translate(args.head, parameter);
2885            anyChanges |= (arg != args.head);
2886            result.append(arg);
2887            if (!anyChanges) return _args;
2888        }
2889        return result.toList();
2890    }
2891
2892    /** Expand a boxing or unboxing conversion if needed. */
2893    @SuppressWarnings("unchecked") // XXX unchecked
2894    <T extends JCExpression> T boxIfNeeded(T tree, Type type) {
2895        boolean havePrimitive = tree.type.isPrimitive();
2896        if (havePrimitive == type.isPrimitive())
2897            return tree;
2898        if (havePrimitive) {
2899            Type unboxedTarget = types.unboxedType(type);
2900            if (!unboxedTarget.hasTag(NONE)) {
2901                if (!types.isSubtype(tree.type, unboxedTarget)) //e.g. Character c = 89;
2902                    tree.type = unboxedTarget.constType(tree.type.constValue());
2903                return (T)boxPrimitive(tree, types.erasure(type));
2904            } else {
2905                tree = (T)boxPrimitive(tree);
2906            }
2907        } else {
2908            tree = (T)unbox(tree, type);
2909        }
2910        return tree;
2911    }
2912
2913    /** Box up a single primitive expression. */
2914    JCExpression boxPrimitive(JCExpression tree) {
2915        return boxPrimitive(tree, types.boxedClass(tree.type).type);
2916    }
2917
2918    /** Box up a single primitive expression. */
2919    JCExpression boxPrimitive(JCExpression tree, Type box) {
2920        make_at(tree.pos());
2921        Symbol valueOfSym = lookupMethod(tree.pos(),
2922                                         names.valueOf,
2923                                         box,
2924                                         List.<Type>nil()
2925                                         .prepend(tree.type));
2926        return make.App(make.QualIdent(valueOfSym), List.of(tree));
2927    }
2928
2929    /** Unbox an object to a primitive value. */
2930    JCExpression unbox(JCExpression tree, Type primitive) {
2931        Type unboxedType = types.unboxedType(tree.type);
2932        if (unboxedType.hasTag(NONE)) {
2933            unboxedType = primitive;
2934            if (!unboxedType.isPrimitive())
2935                throw new AssertionError(unboxedType);
2936            make_at(tree.pos());
2937            tree = make.TypeCast(types.boxedClass(unboxedType).type, tree);
2938        } else {
2939            // There must be a conversion from unboxedType to primitive.
2940            if (!types.isSubtype(unboxedType, primitive))
2941                throw new AssertionError(tree);
2942        }
2943        make_at(tree.pos());
2944        Symbol valueSym = lookupMethod(tree.pos(),
2945                                       unboxedType.tsym.name.append(names.Value), // x.intValue()
2946                                       tree.type,
2947                                       List.nil());
2948        return make.App(make.Select(tree, valueSym));
2949    }
2950
2951    /** Visitor method for parenthesized expressions.
2952     *  If the subexpression has changed, omit the parens.
2953     */
2954    public void visitParens(JCParens tree) {
2955        JCTree expr = translate(tree.expr);
2956        result = ((expr == tree.expr) ? tree : expr);
2957    }
2958
2959    public void visitIndexed(JCArrayAccess tree) {
2960        tree.indexed = translate(tree.indexed);
2961        tree.index = translate(tree.index, syms.intType);
2962        result = tree;
2963    }
2964
2965    public void visitAssign(JCAssign tree) {
2966        tree.lhs = translate(tree.lhs, tree);
2967        tree.rhs = translate(tree.rhs, tree.lhs.type);
2968
2969        // If translated left hand side is an Apply, we are
2970        // seeing an access method invocation. In this case, append
2971        // right hand side as last argument of the access method.
2972        if (tree.lhs.hasTag(APPLY)) {
2973            JCMethodInvocation app = (JCMethodInvocation)tree.lhs;
2974            app.args = List.of(tree.rhs).prependList(app.args);
2975            result = app;
2976        } else {
2977            result = tree;
2978        }
2979    }
2980
2981    public void visitAssignop(final JCAssignOp tree) {
2982        final boolean boxingReq = !tree.lhs.type.isPrimitive() &&
2983            tree.operator.type.getReturnType().isPrimitive();
2984
2985        AssignopDependencyScanner depScanner = new AssignopDependencyScanner(tree);
2986        depScanner.scan(tree.rhs);
2987
2988        if (boxingReq || depScanner.dependencyFound) {
2989            // boxing required; need to rewrite as x = (unbox typeof x)(x op y);
2990            // or if x == (typeof x)z then z = (unbox typeof x)((typeof x)z op y)
2991            // (but without recomputing x)
2992            JCTree newTree = abstractLval(tree.lhs, lhs -> {
2993                Tag newTag = tree.getTag().noAssignOp();
2994                // Erasure (TransTypes) can change the type of
2995                // tree.lhs.  However, we can still get the
2996                // unerased type of tree.lhs as it is stored
2997                // in tree.type in Attr.
2998                OperatorSymbol newOperator = operators.resolveBinary(tree,
2999                                                              newTag,
3000                                                              tree.type,
3001                                                              tree.rhs.type);
3002                //Need to use the "lhs" at two places, once on the future left hand side
3003                //and once in the future binary operator. But further processing may change
3004                //the components of the tree in place (see visitSelect for e.g. <Class>.super.<ident>),
3005                //so cloning the tree to avoid interference between the uses:
3006                JCExpression expr = (JCExpression) lhs.clone();
3007                if (expr.type != tree.type)
3008                    expr = make.TypeCast(tree.type, expr);
3009                JCBinary opResult = make.Binary(newTag, expr, tree.rhs);
3010                opResult.operator = newOperator;
3011                opResult.type = newOperator.type.getReturnType();
3012                JCExpression newRhs = boxingReq ?
3013                    make.TypeCast(types.unboxedType(tree.type), opResult) :
3014                    opResult;
3015                return make.Assign(lhs, newRhs).setType(tree.type);
3016            });
3017            result = translate(newTree);
3018            return;
3019        }
3020        tree.lhs = translate(tree.lhs, tree);
3021        tree.rhs = translate(tree.rhs, tree.operator.type.getParameterTypes().tail.head);
3022
3023        // If translated left hand side is an Apply, we are
3024        // seeing an access method invocation. In this case, append
3025        // right hand side as last argument of the access method.
3026        if (tree.lhs.hasTag(APPLY)) {
3027            JCMethodInvocation app = (JCMethodInvocation)tree.lhs;
3028            // if operation is a += on strings,
3029            // make sure to convert argument to string
3030            JCExpression rhs = tree.operator.opcode == string_add
3031              ? makeString(tree.rhs)
3032              : tree.rhs;
3033            app.args = List.of(rhs).prependList(app.args);
3034            result = app;
3035        } else {
3036            result = tree;
3037        }
3038    }
3039
3040    class AssignopDependencyScanner extends TreeScanner {
3041
3042        Symbol sym;
3043        boolean dependencyFound = false;
3044
3045        AssignopDependencyScanner(JCAssignOp tree) {
3046            this.sym = TreeInfo.symbol(tree.lhs);
3047        }
3048
3049        @Override
3050        public void scan(JCTree tree) {
3051            if (tree != null && sym != null) {
3052                tree.accept(this);
3053            }
3054        }
3055
3056        @Override
3057        public void visitAssignop(JCAssignOp tree) {
3058            if (TreeInfo.symbol(tree.lhs) == sym) {
3059                dependencyFound = true;
3060                return;
3061            }
3062            super.visitAssignop(tree);
3063        }
3064
3065        @Override
3066        public void visitUnary(JCUnary tree) {
3067            if (TreeInfo.symbol(tree.arg) == sym) {
3068                dependencyFound = true;
3069                return;
3070            }
3071            super.visitUnary(tree);
3072        }
3073    }
3074
3075    /** Lower a tree of the form e++ or e-- where e is an object type */
3076    JCExpression lowerBoxedPostop(final JCUnary tree) {
3077        // translate to tmp1=lval(e); tmp2=tmp1; tmp1 OP 1; tmp2
3078        // or
3079        // translate to tmp1=lval(e); tmp2=tmp1; (typeof tree)tmp1 OP 1; tmp2
3080        // where OP is += or -=
3081        final boolean cast = TreeInfo.skipParens(tree.arg).hasTag(TYPECAST);
3082        return abstractLval(tree.arg, tmp1 -> abstractRval(tmp1, tree.arg.type, tmp2 -> {
3083            Tag opcode = (tree.hasTag(POSTINC))
3084                ? PLUS_ASG : MINUS_ASG;
3085            //"tmp1" and "tmp2" may refer to the same instance
3086            //(for e.g. <Class>.super.<ident>). But further processing may
3087            //change the components of the tree in place (see visitSelect),
3088            //so cloning the tree to avoid interference between the two uses:
3089            JCExpression lhs = (JCExpression)tmp1.clone();
3090            lhs = cast
3091                ? make.TypeCast(tree.arg.type, lhs)
3092                : lhs;
3093            JCExpression update = makeAssignop(opcode,
3094                                         lhs,
3095                                         make.Literal(1));
3096            return makeComma(update, tmp2);
3097        }));
3098    }
3099
3100    public void visitUnary(JCUnary tree) {
3101        boolean isUpdateOperator = tree.getTag().isIncOrDecUnaryOp();
3102        if (isUpdateOperator && !tree.arg.type.isPrimitive()) {
3103            switch(tree.getTag()) {
3104            case PREINC:            // ++ e
3105                    // translate to e += 1
3106            case PREDEC:            // -- e
3107                    // translate to e -= 1
3108                {
3109                    JCTree.Tag opcode = (tree.hasTag(PREINC))
3110                        ? PLUS_ASG : MINUS_ASG;
3111                    JCAssignOp newTree = makeAssignop(opcode,
3112                                                    tree.arg,
3113                                                    make.Literal(1));
3114                    result = translate(newTree, tree.type);
3115                    return;
3116                }
3117            case POSTINC:           // e ++
3118            case POSTDEC:           // e --
3119                {
3120                    result = translate(lowerBoxedPostop(tree), tree.type);
3121                    return;
3122                }
3123            }
3124            throw new AssertionError(tree);
3125        }
3126
3127        tree.arg = boxIfNeeded(translate(tree.arg, tree), tree.type);
3128
3129        if (tree.hasTag(NOT) && tree.arg.type.constValue() != null) {
3130            tree.type = cfolder.fold1(bool_not, tree.arg.type);
3131        }
3132
3133        // If translated left hand side is an Apply, we are
3134        // seeing an access method invocation. In this case, return
3135        // that access method invocation as result.
3136        if (isUpdateOperator && tree.arg.hasTag(APPLY)) {
3137            result = tree.arg;
3138        } else {
3139            result = tree;
3140        }
3141    }
3142
3143    public void visitBinary(JCBinary tree) {
3144        List<Type> formals = tree.operator.type.getParameterTypes();
3145        JCTree lhs = tree.lhs = translate(tree.lhs, formals.head);
3146        switch (tree.getTag()) {
3147        case OR:
3148            if (isTrue(lhs)) {
3149                result = lhs;
3150                return;
3151            }
3152            if (isFalse(lhs)) {
3153                result = translate(tree.rhs, formals.tail.head);
3154                return;
3155            }
3156            break;
3157        case AND:
3158            if (isFalse(lhs)) {
3159                result = lhs;
3160                return;
3161            }
3162            if (isTrue(lhs)) {
3163                result = translate(tree.rhs, formals.tail.head);
3164                return;
3165            }
3166            break;
3167        }
3168        tree.rhs = translate(tree.rhs, formals.tail.head);
3169        result = tree;
3170    }
3171
3172    public void visitIdent(JCIdent tree) {
3173        result = access(tree.sym, tree, enclOp, false);
3174    }
3175
3176    /** Translate away the foreach loop.  */
3177    public void visitForeachLoop(JCEnhancedForLoop tree) {
3178        if (types.elemtype(tree.expr.type) == null)
3179            visitIterableForeachLoop(tree);
3180        else
3181            visitArrayForeachLoop(tree);
3182    }
3183        // where
3184        /**
3185         * A statement of the form
3186         *
3187         * <pre>
3188         *     for ( T v : arrayexpr ) stmt;
3189         * </pre>
3190         *
3191         * (where arrayexpr is of an array type) gets translated to
3192         *
3193         * <pre>{@code
3194         *     for ( { arraytype #arr = arrayexpr;
3195         *             int #len = array.length;
3196         *             int #i = 0; };
3197         *           #i < #len; i$++ ) {
3198         *         T v = arr$[#i];
3199         *         stmt;
3200         *     }
3201         * }</pre>
3202         *
3203         * where #arr, #len, and #i are freshly named synthetic local variables.
3204         */
3205        private void visitArrayForeachLoop(JCEnhancedForLoop tree) {
3206            make_at(tree.expr.pos());
3207            VarSymbol arraycache = new VarSymbol(SYNTHETIC,
3208                                                 names.fromString("arr" + target.syntheticNameChar()),
3209                                                 tree.expr.type,
3210                                                 currentMethodSym);
3211            JCStatement arraycachedef = make.VarDef(arraycache, tree.expr);
3212            VarSymbol lencache = new VarSymbol(SYNTHETIC,
3213                                               names.fromString("len" + target.syntheticNameChar()),
3214                                               syms.intType,
3215                                               currentMethodSym);
3216            JCStatement lencachedef = make.
3217                VarDef(lencache, make.Select(make.Ident(arraycache), syms.lengthVar));
3218            VarSymbol index = new VarSymbol(SYNTHETIC,
3219                                            names.fromString("i" + target.syntheticNameChar()),
3220                                            syms.intType,
3221                                            currentMethodSym);
3222
3223            JCVariableDecl indexdef = make.VarDef(index, make.Literal(INT, 0));
3224            indexdef.init.type = indexdef.type = syms.intType.constType(0);
3225
3226            List<JCStatement> loopinit = List.of(arraycachedef, lencachedef, indexdef);
3227            JCBinary cond = makeBinary(LT, make.Ident(index), make.Ident(lencache));
3228
3229            JCExpressionStatement step = make.Exec(makeUnary(PREINC, make.Ident(index)));
3230
3231            Type elemtype = types.elemtype(tree.expr.type);
3232            JCExpression loopvarinit = make.Indexed(make.Ident(arraycache),
3233                                                    make.Ident(index)).setType(elemtype);
3234            JCVariableDecl loopvardef = (JCVariableDecl)make.VarDef(tree.var.mods,
3235                                                  tree.var.name,
3236                                                  tree.var.vartype,
3237                                                  loopvarinit).setType(tree.var.type);
3238            loopvardef.sym = tree.var.sym;
3239            JCBlock body = make.
3240                Block(0, List.of(loopvardef, tree.body));
3241
3242            result = translate(make.
3243                               ForLoop(loopinit,
3244                                       cond,
3245                                       List.of(step),
3246                                       body));
3247            patchTargets(body, tree, result);
3248        }
3249        /** Patch up break and continue targets. */
3250        private void patchTargets(JCTree body, final JCTree src, final JCTree dest) {
3251            class Patcher extends TreeScanner {
3252                public void visitBreak(JCBreak tree) {
3253                    if (tree.target == src)
3254                        tree.target = dest;
3255                }
3256                public void visitContinue(JCContinue tree) {
3257                    if (tree.target == src)
3258                        tree.target = dest;
3259                }
3260                public void visitClassDef(JCClassDecl tree) {}
3261            }
3262            new Patcher().scan(body);
3263        }
3264        /**
3265         * A statement of the form
3266         *
3267         * <pre>
3268         *     for ( T v : coll ) stmt ;
3269         * </pre>
3270         *
3271         * (where coll implements {@code Iterable<? extends T>}) gets translated to
3272         *
3273         * <pre>{@code
3274         *     for ( Iterator<? extends T> #i = coll.iterator(); #i.hasNext(); ) {
3275         *         T v = (T) #i.next();
3276         *         stmt;
3277         *     }
3278         * }</pre>
3279         *
3280         * where #i is a freshly named synthetic local variable.
3281         */
3282        private void visitIterableForeachLoop(JCEnhancedForLoop tree) {
3283            make_at(tree.expr.pos());
3284            Type iteratorTarget = syms.objectType;
3285            Type iterableType = types.asSuper(types.cvarUpperBound(tree.expr.type),
3286                                              syms.iterableType.tsym);
3287            if (iterableType.getTypeArguments().nonEmpty())
3288                iteratorTarget = types.erasure(iterableType.getTypeArguments().head);
3289            Type eType = types.skipTypeVars(tree.expr.type, false);
3290            tree.expr.type = types.erasure(eType);
3291            if (eType.isCompound())
3292                tree.expr = make.TypeCast(types.erasure(iterableType), tree.expr);
3293            Symbol iterator = lookupMethod(tree.expr.pos(),
3294                                           names.iterator,
3295                                           eType,
3296                                           List.nil());
3297            VarSymbol itvar = new VarSymbol(SYNTHETIC, names.fromString("i" + target.syntheticNameChar()),
3298                                            types.erasure(types.asSuper(iterator.type.getReturnType(), syms.iteratorType.tsym)),
3299                                            currentMethodSym);
3300
3301             JCStatement init = make.
3302                VarDef(itvar, make.App(make.Select(tree.expr, iterator)
3303                     .setType(types.erasure(iterator.type))));
3304
3305            Symbol hasNext = lookupMethod(tree.expr.pos(),
3306                                          names.hasNext,
3307                                          itvar.type,
3308                                          List.nil());
3309            JCMethodInvocation cond = make.App(make.Select(make.Ident(itvar), hasNext));
3310            Symbol next = lookupMethod(tree.expr.pos(),
3311                                       names.next,
3312                                       itvar.type,
3313                                       List.nil());
3314            JCExpression vardefinit = make.App(make.Select(make.Ident(itvar), next));
3315            if (tree.var.type.isPrimitive())
3316                vardefinit = make.TypeCast(types.cvarUpperBound(iteratorTarget), vardefinit);
3317            else
3318                vardefinit = make.TypeCast(tree.var.type, vardefinit);
3319            JCVariableDecl indexDef = (JCVariableDecl)make.VarDef(tree.var.mods,
3320                                                  tree.var.name,
3321                                                  tree.var.vartype,
3322                                                  vardefinit).setType(tree.var.type);
3323            indexDef.sym = tree.var.sym;
3324            JCBlock body = make.Block(0, List.of(indexDef, tree.body));
3325            body.endpos = TreeInfo.endPos(tree.body);
3326            result = translate(make.
3327                ForLoop(List.of(init),
3328                        cond,
3329                        List.nil(),
3330                        body));
3331            patchTargets(body, tree, result);
3332        }
3333
3334    public void visitVarDef(JCVariableDecl tree) {
3335        MethodSymbol oldMethodSym = currentMethodSym;
3336        tree.mods = translate(tree.mods);
3337        tree.vartype = translate(tree.vartype);
3338        if (currentMethodSym == null) {
3339            // A class or instance field initializer.
3340            currentMethodSym =
3341                new MethodSymbol((tree.mods.flags&STATIC) | BLOCK,
3342                                 names.empty, null,
3343                                 currentClass);
3344        }
3345        if (tree.init != null) tree.init = translate(tree.init, tree.type);
3346        result = tree;
3347        currentMethodSym = oldMethodSym;
3348    }
3349
3350    public void visitBlock(JCBlock tree) {
3351        MethodSymbol oldMethodSym = currentMethodSym;
3352        if (currentMethodSym == null) {
3353            // Block is a static or instance initializer.
3354            currentMethodSym =
3355                new MethodSymbol(tree.flags | BLOCK,
3356                                 names.empty, null,
3357                                 currentClass);
3358        }
3359        super.visitBlock(tree);
3360        currentMethodSym = oldMethodSym;
3361    }
3362
3363    public void visitDoLoop(JCDoWhileLoop tree) {
3364        tree.body = translate(tree.body);
3365        tree.cond = translate(tree.cond, syms.booleanType);
3366        result = tree;
3367    }
3368
3369    public void visitWhileLoop(JCWhileLoop tree) {
3370        tree.cond = translate(tree.cond, syms.booleanType);
3371        tree.body = translate(tree.body);
3372        result = tree;
3373    }
3374
3375    public void visitForLoop(JCForLoop tree) {
3376        tree.init = translate(tree.init);
3377        if (tree.cond != null)
3378            tree.cond = translate(tree.cond, syms.booleanType);
3379        tree.step = translate(tree.step);
3380        tree.body = translate(tree.body);
3381        result = tree;
3382    }
3383
3384    public void visitReturn(JCReturn tree) {
3385        if (tree.expr != null)
3386            tree.expr = translate(tree.expr,
3387                                  types.erasure(currentMethodDef
3388                                                .restype.type));
3389        result = tree;
3390    }
3391
3392    public void visitSwitch(JCSwitch tree) {
3393        Type selsuper = types.supertype(tree.selector.type);
3394        boolean enumSwitch = selsuper != null &&
3395            (tree.selector.type.tsym.flags() & ENUM) != 0;
3396        boolean stringSwitch = selsuper != null &&
3397            types.isSameType(tree.selector.type, syms.stringType);
3398        Type target = enumSwitch ? tree.selector.type :
3399            (stringSwitch? syms.stringType : syms.intType);
3400        tree.selector = translate(tree.selector, target);
3401        tree.cases = translateCases(tree.cases);
3402        if (enumSwitch) {
3403            result = visitEnumSwitch(tree);
3404        } else if (stringSwitch) {
3405            result = visitStringSwitch(tree);
3406        } else {
3407            result = tree;
3408        }
3409    }
3410
3411    public JCTree visitEnumSwitch(JCSwitch tree) {
3412        TypeSymbol enumSym = tree.selector.type.tsym;
3413        EnumMapping map = mapForEnum(tree.pos(), enumSym);
3414        make_at(tree.pos());
3415        Symbol ordinalMethod = lookupMethod(tree.pos(),
3416                                            names.ordinal,
3417                                            tree.selector.type,
3418                                            List.nil());
3419        JCArrayAccess selector = make.Indexed(map.mapVar,
3420                                        make.App(make.Select(tree.selector,
3421                                                             ordinalMethod)));
3422        ListBuffer<JCCase> cases = new ListBuffer<>();
3423        for (JCCase c : tree.cases) {
3424            if (c.pat != null) {
3425                VarSymbol label = (VarSymbol)TreeInfo.symbol(c.pat);
3426                JCLiteral pat = map.forConstant(label);
3427                cases.append(make.Case(pat, c.stats));
3428            } else {
3429                cases.append(c);
3430            }
3431        }
3432        JCSwitch enumSwitch = make.Switch(selector, cases.toList());
3433        patchTargets(enumSwitch, tree, enumSwitch);
3434        return enumSwitch;
3435    }
3436
3437    public JCTree visitStringSwitch(JCSwitch tree) {
3438        List<JCCase> caseList = tree.getCases();
3439        int alternatives = caseList.size();
3440
3441        if (alternatives == 0) { // Strange but legal possibility
3442            return make.at(tree.pos()).Exec(attr.makeNullCheck(tree.getExpression()));
3443        } else {
3444            /*
3445             * The general approach used is to translate a single
3446             * string switch statement into a series of two chained
3447             * switch statements: the first a synthesized statement
3448             * switching on the argument string's hash value and
3449             * computing a string's position in the list of original
3450             * case labels, if any, followed by a second switch on the
3451             * computed integer value.  The second switch has the same
3452             * code structure as the original string switch statement
3453             * except that the string case labels are replaced with
3454             * positional integer constants starting at 0.
3455             *
3456             * The first switch statement can be thought of as an
3457             * inlined map from strings to their position in the case
3458             * label list.  An alternate implementation would use an
3459             * actual Map for this purpose, as done for enum switches.
3460             *
3461             * With some additional effort, it would be possible to
3462             * use a single switch statement on the hash code of the
3463             * argument, but care would need to be taken to preserve
3464             * the proper control flow in the presence of hash
3465             * collisions and other complications, such as
3466             * fallthroughs.  Switch statements with one or two
3467             * alternatives could also be specially translated into
3468             * if-then statements to omit the computation of the hash
3469             * code.
3470             *
3471             * The generated code assumes that the hashing algorithm
3472             * of String is the same in the compilation environment as
3473             * in the environment the code will run in.  The string
3474             * hashing algorithm in the SE JDK has been unchanged
3475             * since at least JDK 1.2.  Since the algorithm has been
3476             * specified since that release as well, it is very
3477             * unlikely to be changed in the future.
3478             *
3479             * Different hashing algorithms, such as the length of the
3480             * strings or a perfect hashing algorithm over the
3481             * particular set of case labels, could potentially be
3482             * used instead of String.hashCode.
3483             */
3484
3485            ListBuffer<JCStatement> stmtList = new ListBuffer<>();
3486
3487            // Map from String case labels to their original position in
3488            // the list of case labels.
3489            Map<String, Integer> caseLabelToPosition = new LinkedHashMap<>(alternatives + 1, 1.0f);
3490
3491            // Map of hash codes to the string case labels having that hashCode.
3492            Map<Integer, Set<String>> hashToString = new LinkedHashMap<>(alternatives + 1, 1.0f);
3493
3494            int casePosition = 0;
3495            for(JCCase oneCase : caseList) {
3496                JCExpression expression = oneCase.getExpression();
3497
3498                if (expression != null) { // expression for a "default" case is null
3499                    String labelExpr = (String) expression.type.constValue();
3500                    Integer mapping = caseLabelToPosition.put(labelExpr, casePosition);
3501                    Assert.checkNull(mapping);
3502                    int hashCode = labelExpr.hashCode();
3503
3504                    Set<String> stringSet = hashToString.get(hashCode);
3505                    if (stringSet == null) {
3506                        stringSet = new LinkedHashSet<>(1, 1.0f);
3507                        stringSet.add(labelExpr);
3508                        hashToString.put(hashCode, stringSet);
3509                    } else {
3510                        boolean added = stringSet.add(labelExpr);
3511                        Assert.check(added);
3512                    }
3513                }
3514                casePosition++;
3515            }
3516
3517            // Synthesize a switch statement that has the effect of
3518            // mapping from a string to the integer position of that
3519            // string in the list of case labels.  This is done by
3520            // switching on the hashCode of the string followed by an
3521            // if-then-else chain comparing the input for equality
3522            // with all the case labels having that hash value.
3523
3524            /*
3525             * s$ = top of stack;
3526             * tmp$ = -1;
3527             * switch($s.hashCode()) {
3528             *     case caseLabel.hashCode:
3529             *         if (s$.equals("caseLabel_1")
3530             *           tmp$ = caseLabelToPosition("caseLabel_1");
3531             *         else if (s$.equals("caseLabel_2"))
3532             *           tmp$ = caseLabelToPosition("caseLabel_2");
3533             *         ...
3534             *         break;
3535             * ...
3536             * }
3537             */
3538
3539            VarSymbol dollar_s = new VarSymbol(FINAL|SYNTHETIC,
3540                                               names.fromString("s" + tree.pos + target.syntheticNameChar()),
3541                                               syms.stringType,
3542                                               currentMethodSym);
3543            stmtList.append(make.at(tree.pos()).VarDef(dollar_s, tree.getExpression()).setType(dollar_s.type));
3544
3545            VarSymbol dollar_tmp = new VarSymbol(SYNTHETIC,
3546                                                 names.fromString("tmp" + tree.pos + target.syntheticNameChar()),
3547                                                 syms.intType,
3548                                                 currentMethodSym);
3549            JCVariableDecl dollar_tmp_def =
3550                (JCVariableDecl)make.VarDef(dollar_tmp, make.Literal(INT, -1)).setType(dollar_tmp.type);
3551            dollar_tmp_def.init.type = dollar_tmp.type = syms.intType;
3552            stmtList.append(dollar_tmp_def);
3553            ListBuffer<JCCase> caseBuffer = new ListBuffer<>();
3554            // hashCode will trigger nullcheck on original switch expression
3555            JCMethodInvocation hashCodeCall = makeCall(make.Ident(dollar_s),
3556                                                       names.hashCode,
3557                                                       List.nil()).setType(syms.intType);
3558            JCSwitch switch1 = make.Switch(hashCodeCall,
3559                                        caseBuffer.toList());
3560            for(Map.Entry<Integer, Set<String>> entry : hashToString.entrySet()) {
3561                int hashCode = entry.getKey();
3562                Set<String> stringsWithHashCode = entry.getValue();
3563                Assert.check(stringsWithHashCode.size() >= 1);
3564
3565                JCStatement elsepart = null;
3566                for(String caseLabel : stringsWithHashCode ) {
3567                    JCMethodInvocation stringEqualsCall = makeCall(make.Ident(dollar_s),
3568                                                                   names.equals,
3569                                                                   List.of(make.Literal(caseLabel)));
3570                    elsepart = make.If(stringEqualsCall,
3571                                       make.Exec(make.Assign(make.Ident(dollar_tmp),
3572                                                             make.Literal(caseLabelToPosition.get(caseLabel))).
3573                                                 setType(dollar_tmp.type)),
3574                                       elsepart);
3575                }
3576
3577                ListBuffer<JCStatement> lb = new ListBuffer<>();
3578                JCBreak breakStmt = make.Break(null);
3579                breakStmt.target = switch1;
3580                lb.append(elsepart).append(breakStmt);
3581
3582                caseBuffer.append(make.Case(make.Literal(hashCode), lb.toList()));
3583            }
3584
3585            switch1.cases = caseBuffer.toList();
3586            stmtList.append(switch1);
3587
3588            // Make isomorphic switch tree replacing string labels
3589            // with corresponding integer ones from the label to
3590            // position map.
3591
3592            ListBuffer<JCCase> lb = new ListBuffer<>();
3593            JCSwitch switch2 = make.Switch(make.Ident(dollar_tmp), lb.toList());
3594            for(JCCase oneCase : caseList ) {
3595                // Rewire up old unlabeled break statements to the
3596                // replacement switch being created.
3597                patchTargets(oneCase, tree, switch2);
3598
3599                boolean isDefault = (oneCase.getExpression() == null);
3600                JCExpression caseExpr;
3601                if (isDefault)
3602                    caseExpr = null;
3603                else {
3604                    caseExpr = make.Literal(caseLabelToPosition.get((String)TreeInfo.skipParens(oneCase.
3605                                                                                                getExpression()).
3606                                                                    type.constValue()));
3607                }
3608
3609                lb.append(make.Case(caseExpr,
3610                                    oneCase.getStatements()));
3611            }
3612
3613            switch2.cases = lb.toList();
3614            stmtList.append(switch2);
3615
3616            return make.Block(0L, stmtList.toList());
3617        }
3618    }
3619
3620    public void visitNewArray(JCNewArray tree) {
3621        tree.elemtype = translate(tree.elemtype);
3622        for (List<JCExpression> t = tree.dims; t.tail != null; t = t.tail)
3623            if (t.head != null) t.head = translate(t.head, syms.intType);
3624        tree.elems = translate(tree.elems, types.elemtype(tree.type));
3625        result = tree;
3626    }
3627
3628    public void visitSelect(JCFieldAccess tree) {
3629        // need to special case-access of the form C.super.x
3630        // these will always need an access method, unless C
3631        // is a default interface subclassed by the current class.
3632        boolean qualifiedSuperAccess =
3633            tree.selected.hasTag(SELECT) &&
3634            TreeInfo.name(tree.selected) == names._super &&
3635            !types.isDirectSuperInterface(((JCFieldAccess)tree.selected).selected.type.tsym, currentClass);
3636        tree.selected = translate(tree.selected);
3637        if (tree.name == names._class) {
3638            result = classOf(tree.selected);
3639        }
3640        else if (tree.name == names._super &&
3641                types.isDirectSuperInterface(tree.selected.type.tsym, currentClass)) {
3642            //default super call!! Not a classic qualified super call
3643            TypeSymbol supSym = tree.selected.type.tsym;
3644            Assert.checkNonNull(types.asSuper(currentClass.type, supSym));
3645            result = tree;
3646        }
3647        else if (tree.name == names._this || tree.name == names._super) {
3648            result = makeThis(tree.pos(), tree.selected.type.tsym);
3649        }
3650        else
3651            result = access(tree.sym, tree, enclOp, qualifiedSuperAccess);
3652    }
3653
3654    public void visitLetExpr(LetExpr tree) {
3655        tree.defs = translateVarDefs(tree.defs);
3656        tree.expr = translate(tree.expr, tree.type);
3657        result = tree;
3658    }
3659
3660    // There ought to be nothing to rewrite here;
3661    // we don't generate code.
3662    public void visitAnnotation(JCAnnotation tree) {
3663        result = tree;
3664    }
3665
3666    @Override
3667    public void visitTry(JCTry tree) {
3668        if (tree.resources.nonEmpty()) {
3669            result = makeTwrTry(tree);
3670            return;
3671        }
3672
3673        boolean hasBody = tree.body.getStatements().nonEmpty();
3674        boolean hasCatchers = tree.catchers.nonEmpty();
3675        boolean hasFinally = tree.finalizer != null &&
3676                tree.finalizer.getStatements().nonEmpty();
3677
3678        if (!hasCatchers && !hasFinally) {
3679            result = translate(tree.body);
3680            return;
3681        }
3682
3683        if (!hasBody) {
3684            if (hasFinally) {
3685                result = translate(tree.finalizer);
3686            } else {
3687                result = translate(tree.body);
3688            }
3689            return;
3690        }
3691
3692        // no optimizations possible
3693        super.visitTry(tree);
3694    }
3695
3696/**************************************************************************
3697 * main method
3698 *************************************************************************/
3699
3700    /** Translate a toplevel class and return a list consisting of
3701     *  the translated class and translated versions of all inner classes.
3702     *  @param env   The attribution environment current at the class definition.
3703     *               We need this for resolving some additional symbols.
3704     *  @param cdef  The tree representing the class definition.
3705     */
3706    public List<JCTree> translateTopLevelClass(Env<AttrContext> env, JCTree cdef, TreeMaker make) {
3707        ListBuffer<JCTree> translated = null;
3708        try {
3709            attrEnv = env;
3710            this.make = make;
3711            endPosTable = env.toplevel.endPositions;
3712            currentClass = null;
3713            currentMethodDef = null;
3714            outermostClassDef = (cdef.hasTag(CLASSDEF)) ? (JCClassDecl)cdef : null;
3715            outermostMemberDef = null;
3716            this.translated = new ListBuffer<>();
3717            classdefs = new HashMap<>();
3718            actualSymbols = new HashMap<>();
3719            freevarCache = new HashMap<>();
3720            proxies = WriteableScope.create(syms.noSymbol);
3721            twrVars = WriteableScope.create(syms.noSymbol);
3722            outerThisStack = List.nil();
3723            accessNums = new HashMap<>();
3724            accessSyms = new HashMap<>();
3725            accessConstrs = new HashMap<>();
3726            accessConstrTags = List.nil();
3727            accessed = new ListBuffer<>();
3728            translate(cdef, (JCExpression)null);
3729            for (List<Symbol> l = accessed.toList(); l.nonEmpty(); l = l.tail)
3730                makeAccessible(l.head);
3731            for (EnumMapping map : enumSwitchMap.values())
3732                map.translate();
3733            checkConflicts(this.translated.toList());
3734            checkAccessConstructorTags();
3735            translated = this.translated;
3736        } finally {
3737            // note that recursive invocations of this method fail hard
3738            attrEnv = null;
3739            this.make = null;
3740            endPosTable = null;
3741            currentClass = null;
3742            currentMethodDef = null;
3743            outermostClassDef = null;
3744            outermostMemberDef = null;
3745            this.translated = null;
3746            classdefs = null;
3747            actualSymbols = null;
3748            freevarCache = null;
3749            proxies = null;
3750            outerThisStack = null;
3751            accessNums = null;
3752            accessSyms = null;
3753            accessConstrs = null;
3754            accessConstrTags = null;
3755            accessed = null;
3756            enumSwitchMap.clear();
3757            assertionsDisabledClassCache = null;
3758        }
3759        return translated.toList();
3760    }
3761}
3762