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
26 package com.sun.tools.javac.comp;
27
28 import java.util.*;
29
30 import com.sun.tools.javac.code.*;
31 import com.sun.tools.javac.code.Kinds.KindSelector;
32 import com.sun.tools.javac.code.Scope.WriteableScope;
33 import com.sun.tools.javac.jvm.*;
34 import com.sun.tools.javac.main.Option.PkgInfo;
35 import com.sun.tools.javac.resources.CompilerProperties.Fragments;
36 import com.sun.tools.javac.tree.*;
37 import com.sun.tools.javac.util.*;
38 import com.sun.tools.javac.util.JCDiagnostic.DiagnosticPosition;
39 import com.sun.tools.javac.util.List;
40
41 import com.sun.tools.javac.code.Symbol.*;
42 import com.sun.tools.javac.code.Symbol.OperatorSymbol.AccessCode;
43 import com.sun.tools.javac.resources.CompilerProperties.Errors;
44 import com.sun.tools.javac.tree.JCTree.*;
45 import com.sun.tools.javac.code.Type.*;
46
47 import com.sun.tools.javac.jvm.Target;
48 import com.sun.tools.javac.tree.EndPosTable;
49
50 import static com.sun.tools.javac.code.Flags.*;
51 import static com.sun.tools.javac.code.Flags.BLOCK;
52 import static com.sun.tools.javac.code.Scope.LookupKind.NON_RECURSIVE;
53 import static com.sun.tools.javac.code.TypeTag.*;
54 import static com.sun.tools.javac.code.Kinds.Kind.*;
55 import static com.sun.tools.javac.code.Symbol.OperatorSymbol.AccessCode.DEREF;
56 import static com.sun.tools.javac.jvm.ByteCodes.*;
57 import static com.sun.tools.javac.tree.JCTree.JCOperatorExpression.OperandPos.LEFT;
58 import static com.sun.tools.javac.tree.JCTree.Tag.*;
59
60 /** This pass translates away some syntactic sugar: inner classes,
61 * class literals, assertions, foreach loops, etc.
62 *
63 * <p><b>This is NOT part of any supported API.
64 * If you write code that depends on this, you do so at your own risk.
65 * This code and its internal interfaces are subject to change or
66 * deletion without notice.</b>
67 */
68 public class Lower extends TreeTranslator {
69 protected static final Context.Key<Lower> lowerKey = new Context.Key<>();
70
71 public static Lower instance(Context context) {
72 Lower instance = context.get(lowerKey);
73 if (instance == null)
74 instance = new Lower(context);
75 return instance;
76 }
246 abstract void visitSymbol(Symbol _sym);
247
248 /** If tree refers to a class instance creation expression
249 * add all free variables of the freshly created class.
250 */
251 public void visitNewClass(JCNewClass tree) {
252 ClassSymbol c = (ClassSymbol)tree.constructor.owner;
253 addFreeVars(c);
254 super.visitNewClass(tree);
255 }
256
257 /** If tree refers to a superclass constructor call,
258 * add all free variables of the superclass.
259 */
260 public void visitApply(JCMethodInvocation tree) {
261 if (TreeInfo.name(tree.meth) == names._super) {
262 addFreeVars((ClassSymbol) TreeInfo.symbol(tree.meth).owner);
263 }
264 super.visitApply(tree);
265 }
266 }
267
268 /**
269 * Lower-specific subclass of {@code BasicFreeVarCollector}.
270 */
271 class FreeVarCollector extends BasicFreeVarCollector {
272
273 /** The owner of the local class.
274 */
275 Symbol owner;
276
277 /** The local class.
278 */
279 ClassSymbol clazz;
280
281 /** The list of owner's variables accessed from within the local class,
282 * without any duplicates.
283 */
284 List<VarSymbol> fvs;
285
347 tree.selected.type.tsym != clazz &&
348 outerThisStack.head != null)
349 visitSymbol(outerThisStack.head);
350 super.visitSelect(tree);
351 }
352
353 /** If tree refers to a superclass constructor call,
354 * add all free variables of the superclass.
355 */
356 public void visitApply(JCMethodInvocation tree) {
357 if (TreeInfo.name(tree.meth) == names._super) {
358 Symbol constructor = TreeInfo.symbol(tree.meth);
359 ClassSymbol c = (ClassSymbol)constructor.owner;
360 if (c.hasOuterInstance() &&
361 !tree.meth.hasTag(SELECT) &&
362 outerThisStack.head != null)
363 visitSymbol(outerThisStack.head);
364 }
365 super.visitApply(tree);
366 }
367 }
368
369 ClassSymbol ownerToCopyFreeVarsFrom(ClassSymbol c) {
370 if (!c.isLocal()) {
371 return null;
372 }
373 Symbol currentOwner = c.owner;
374 while (currentOwner.owner.kind.matches(KindSelector.TYP) && currentOwner.isLocal()) {
375 currentOwner = currentOwner.owner;
376 }
377 if (currentOwner.owner.kind.matches(KindSelector.VAL_MTH) && c.isSubClass(currentOwner, types)) {
378 return (ClassSymbol)currentOwner;
379 }
380 return null;
381 }
382
383 /** Return the variables accessed from within a local class, which
384 * are declared in the local class' owner.
385 * (in reverse order of first access).
386 */
3323 }
3324
3325 public void visitForLoop(JCForLoop tree) {
3326 tree.init = translate(tree.init);
3327 if (tree.cond != null)
3328 tree.cond = translate(tree.cond, syms.booleanType);
3329 tree.step = translate(tree.step);
3330 tree.body = translate(tree.body);
3331 result = tree;
3332 }
3333
3334 public void visitReturn(JCReturn tree) {
3335 if (tree.expr != null)
3336 tree.expr = translate(tree.expr,
3337 types.erasure(currentMethodDef
3338 .restype.type));
3339 result = tree;
3340 }
3341
3342 public void visitSwitch(JCSwitch tree) {
3343 Type selsuper = types.supertype(tree.selector.type);
3344 boolean enumSwitch = selsuper != null &&
3345 (tree.selector.type.tsym.flags() & ENUM) != 0;
3346 boolean stringSwitch = selsuper != null &&
3347 types.isSameType(tree.selector.type, syms.stringType);
3348 Type target = enumSwitch ? tree.selector.type :
3349 (stringSwitch? syms.stringType : syms.intType);
3350 tree.selector = translate(tree.selector, target);
3351 tree.cases = translateCases(tree.cases);
3352 if (enumSwitch) {
3353 result = visitEnumSwitch(tree);
3354 } else if (stringSwitch) {
3355 result = visitStringSwitch(tree);
3356 } else {
3357 result = tree;
3358 }
3359 }
3360
3361 public JCTree visitEnumSwitch(JCSwitch tree) {
3362 TypeSymbol enumSym = tree.selector.type.tsym;
3363 EnumMapping map = mapForEnum(tree.pos(), enumSym);
3364 make_at(tree.pos());
3365 Symbol ordinalMethod = lookupMethod(tree.pos(),
3366 names.ordinal,
3367 tree.selector.type,
3368 List.nil());
3369 JCArrayAccess selector = make.Indexed(map.mapVar,
3370 make.App(make.Select(tree.selector,
3371 ordinalMethod)));
3372 ListBuffer<JCCase> cases = new ListBuffer<>();
3373 for (JCCase c : tree.cases) {
3374 if (c.pat != null) {
3375 VarSymbol label = (VarSymbol)TreeInfo.symbol(c.pat);
3376 JCLiteral pat = map.forConstant(label);
3377 cases.append(make.Case(pat, c.stats));
3378 } else {
3379 cases.append(c);
3380 }
3381 }
3382 JCSwitch enumSwitch = make.Switch(selector, cases.toList());
3383 patchTargets(enumSwitch, tree, enumSwitch);
3384 return enumSwitch;
3385 }
3386
3387 public JCTree visitStringSwitch(JCSwitch tree) {
3388 List<JCCase> caseList = tree.getCases();
3389 int alternatives = caseList.size();
3390
3391 if (alternatives == 0) { // Strange but legal possibility
3392 return make.at(tree.pos()).Exec(attr.makeNullCheck(tree.getExpression()));
3393 } else {
3394 /*
3395 * The general approach used is to translate a single
3396 * string switch statement into a series of two chained
3397 * switch statements: the first a synthesized statement
3425 * since at least JDK 1.2. Since the algorithm has been
3426 * specified since that release as well, it is very
3427 * unlikely to be changed in the future.
3428 *
3429 * Different hashing algorithms, such as the length of the
3430 * strings or a perfect hashing algorithm over the
3431 * particular set of case labels, could potentially be
3432 * used instead of String.hashCode.
3433 */
3434
3435 ListBuffer<JCStatement> stmtList = new ListBuffer<>();
3436
3437 // Map from String case labels to their original position in
3438 // the list of case labels.
3439 Map<String, Integer> caseLabelToPosition = new LinkedHashMap<>(alternatives + 1, 1.0f);
3440
3441 // Map of hash codes to the string case labels having that hashCode.
3442 Map<Integer, Set<String>> hashToString = new LinkedHashMap<>(alternatives + 1, 1.0f);
3443
3444 int casePosition = 0;
3445 for(JCCase oneCase : caseList) {
3446 JCExpression expression = oneCase.getExpression();
3447
3448 if (expression != null) { // expression for a "default" case is null
3449 String labelExpr = (String) expression.type.constValue();
3450 Integer mapping = caseLabelToPosition.put(labelExpr, casePosition);
3451 Assert.checkNull(mapping);
3452 int hashCode = labelExpr.hashCode();
3453
3454 Set<String> stringSet = hashToString.get(hashCode);
3455 if (stringSet == null) {
3456 stringSet = new LinkedHashSet<>(1, 1.0f);
3457 stringSet.add(labelExpr);
3458 hashToString.put(hashCode, stringSet);
3459 } else {
3460 boolean added = stringSet.add(labelExpr);
3461 Assert.check(added);
3462 }
3463 }
3464 casePosition++;
3465 }
3466
3467 // Synthesize a switch statement that has the effect of
3468 // mapping from a string to the integer position of that
3512 Set<String> stringsWithHashCode = entry.getValue();
3513 Assert.check(stringsWithHashCode.size() >= 1);
3514
3515 JCStatement elsepart = null;
3516 for(String caseLabel : stringsWithHashCode ) {
3517 JCMethodInvocation stringEqualsCall = makeCall(make.Ident(dollar_s),
3518 names.equals,
3519 List.of(make.Literal(caseLabel)));
3520 elsepart = make.If(stringEqualsCall,
3521 make.Exec(make.Assign(make.Ident(dollar_tmp),
3522 make.Literal(caseLabelToPosition.get(caseLabel))).
3523 setType(dollar_tmp.type)),
3524 elsepart);
3525 }
3526
3527 ListBuffer<JCStatement> lb = new ListBuffer<>();
3528 JCBreak breakStmt = make.Break(null);
3529 breakStmt.target = switch1;
3530 lb.append(elsepart).append(breakStmt);
3531
3532 caseBuffer.append(make.Case(make.Literal(hashCode), lb.toList()));
3533 }
3534
3535 switch1.cases = caseBuffer.toList();
3536 stmtList.append(switch1);
3537
3538 // Make isomorphic switch tree replacing string labels
3539 // with corresponding integer ones from the label to
3540 // position map.
3541
3542 ListBuffer<JCCase> lb = new ListBuffer<>();
3543 JCSwitch switch2 = make.Switch(make.Ident(dollar_tmp), lb.toList());
3544 for(JCCase oneCase : caseList ) {
3545 // Rewire up old unlabeled break statements to the
3546 // replacement switch being created.
3547 patchTargets(oneCase, tree, switch2);
3548
3549 boolean isDefault = (oneCase.getExpression() == null);
3550 JCExpression caseExpr;
3551 if (isDefault)
3552 caseExpr = null;
3553 else {
3554 caseExpr = make.Literal(caseLabelToPosition.get((String)TreeInfo.skipParens(oneCase.
3555 getExpression()).
3556 type.constValue()));
3557 }
3558
3559 lb.append(make.Case(caseExpr,
3560 oneCase.getStatements()));
3561 }
3562
3563 switch2.cases = lb.toList();
3564 stmtList.append(switch2);
3565
3566 return make.Block(0L, stmtList.toList());
3567 }
3568 }
3569
3570 public void visitNewArray(JCNewArray tree) {
3571 tree.elemtype = translate(tree.elemtype);
3572 for (List<JCExpression> t = tree.dims; t.tail != null; t = t.tail)
3573 if (t.head != null) t.head = translate(t.head, syms.intType);
3574 tree.elems = translate(tree.elems, types.elemtype(tree.type));
3575 result = tree;
3576 }
3577
3578 public void visitSelect(JCFieldAccess tree) {
3579 // need to special case-access of the form C.super.x
3580 // these will always need an access method, unless C
3581 // is a default interface subclassed by the current class.
3582 boolean qualifiedSuperAccess =
3583 tree.selected.hasTag(SELECT) &&
3584 TreeInfo.name(tree.selected) == names._super &&
3585 !types.isDirectSuperInterface(((JCFieldAccess)tree.selected).selected.type.tsym, currentClass);
3586 tree.selected = translate(tree.selected);
3587 if (tree.name == names._class) {
3588 result = classOf(tree.selected);
3589 }
3590 else if (tree.name == names._super &&
3591 types.isDirectSuperInterface(tree.selected.type.tsym, currentClass)) {
3592 //default super call!! Not a classic qualified super call
3593 TypeSymbol supSym = tree.selected.type.tsym;
3594 Assert.checkNonNull(types.asSuper(currentClass.type, supSym));
3595 result = tree;
3596 }
3597 else if (tree.name == names._this || tree.name == names._super) {
3598 result = makeThis(tree.pos(), tree.selected.type.tsym);
3599 }
3600 else
3601 result = access(tree.sym, tree, enclOp, qualifiedSuperAccess);
3602 }
3603
3604 public void visitLetExpr(LetExpr tree) {
3605 tree.defs = translateVarDefs(tree.defs);
3606 tree.expr = translate(tree.expr, tree.type);
3607 result = tree;
3608 }
3609
3610 // There ought to be nothing to rewrite here;
3611 // we don't generate code.
3612 public void visitAnnotation(JCAnnotation tree) {
3613 result = tree;
3614 }
3615
3616 @Override
3617 public void visitTry(JCTry tree) {
3618 if (tree.resources.nonEmpty()) {
3619 result = makeTwrTry(tree);
3620 return;
3621 }
3622
3623 boolean hasBody = tree.body.getStatements().nonEmpty();
3624 boolean hasCatchers = tree.catchers.nonEmpty();
3625 boolean hasFinally = tree.finalizer != null &&
|
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
26 package com.sun.tools.javac.comp;
27
28 import java.util.*;
29 import java.util.Map.Entry;
30 import java.util.function.Function;
31 import java.util.stream.Stream;
32
33 import com.sun.source.tree.CaseTree.CaseKind;
34 import com.sun.tools.javac.code.*;
35 import com.sun.tools.javac.code.Kinds.KindSelector;
36 import com.sun.tools.javac.code.Scope.WriteableScope;
37 import com.sun.tools.javac.jvm.*;
38 import com.sun.tools.javac.main.Option.PkgInfo;
39 import com.sun.tools.javac.resources.CompilerProperties.Fragments;
40 import com.sun.tools.javac.tree.*;
41 import com.sun.tools.javac.util.*;
42 import com.sun.tools.javac.util.JCDiagnostic.DiagnosticPosition;
43 import com.sun.tools.javac.util.List;
44
45 import com.sun.tools.javac.code.Symbol.*;
46 import com.sun.tools.javac.code.Symbol.OperatorSymbol.AccessCode;
47 import com.sun.tools.javac.resources.CompilerProperties.Errors;
48 import com.sun.tools.javac.tree.JCTree.*;
49 import com.sun.tools.javac.code.Type.*;
50
51 import com.sun.tools.javac.jvm.Target;
52 import com.sun.tools.javac.tree.EndPosTable;
53
54 import static com.sun.tools.javac.code.Flags.*;
55 import static com.sun.tools.javac.code.Flags.BLOCK;
56 import static com.sun.tools.javac.code.Scope.LookupKind.NON_RECURSIVE;
57 import static com.sun.tools.javac.code.TypeTag.*;
58 import static com.sun.tools.javac.code.Kinds.Kind.*;
59 import static com.sun.tools.javac.code.Symbol.OperatorSymbol.AccessCode.DEREF;
60 import static com.sun.tools.javac.jvm.ByteCodes.*;
61 import com.sun.tools.javac.tree.JCTree.JCBreak;
62 import com.sun.tools.javac.tree.JCTree.JCCase;
63 import com.sun.tools.javac.tree.JCTree.JCExpression;
64 import com.sun.tools.javac.tree.JCTree.JCExpressionStatement;
65 import static com.sun.tools.javac.tree.JCTree.JCOperatorExpression.OperandPos.LEFT;
66 import static com.sun.tools.javac.tree.JCTree.Tag.*;
67
68 /** This pass translates away some syntactic sugar: inner classes,
69 * class literals, assertions, foreach loops, etc.
70 *
71 * <p><b>This is NOT part of any supported API.
72 * If you write code that depends on this, you do so at your own risk.
73 * This code and its internal interfaces are subject to change or
74 * deletion without notice.</b>
75 */
76 public class Lower extends TreeTranslator {
77 protected static final Context.Key<Lower> lowerKey = new Context.Key<>();
78
79 public static Lower instance(Context context) {
80 Lower instance = context.get(lowerKey);
81 if (instance == null)
82 instance = new Lower(context);
83 return instance;
84 }
254 abstract void visitSymbol(Symbol _sym);
255
256 /** If tree refers to a class instance creation expression
257 * add all free variables of the freshly created class.
258 */
259 public void visitNewClass(JCNewClass tree) {
260 ClassSymbol c = (ClassSymbol)tree.constructor.owner;
261 addFreeVars(c);
262 super.visitNewClass(tree);
263 }
264
265 /** If tree refers to a superclass constructor call,
266 * add all free variables of the superclass.
267 */
268 public void visitApply(JCMethodInvocation tree) {
269 if (TreeInfo.name(tree.meth) == names._super) {
270 addFreeVars((ClassSymbol) TreeInfo.symbol(tree.meth).owner);
271 }
272 super.visitApply(tree);
273 }
274
275 @Override
276 public void visitBreak(JCBreak tree) {
277 if (tree.isValueBreak())
278 scan(tree.value);
279 }
280
281 }
282
283 /**
284 * Lower-specific subclass of {@code BasicFreeVarCollector}.
285 */
286 class FreeVarCollector extends BasicFreeVarCollector {
287
288 /** The owner of the local class.
289 */
290 Symbol owner;
291
292 /** The local class.
293 */
294 ClassSymbol clazz;
295
296 /** The list of owner's variables accessed from within the local class,
297 * without any duplicates.
298 */
299 List<VarSymbol> fvs;
300
362 tree.selected.type.tsym != clazz &&
363 outerThisStack.head != null)
364 visitSymbol(outerThisStack.head);
365 super.visitSelect(tree);
366 }
367
368 /** If tree refers to a superclass constructor call,
369 * add all free variables of the superclass.
370 */
371 public void visitApply(JCMethodInvocation tree) {
372 if (TreeInfo.name(tree.meth) == names._super) {
373 Symbol constructor = TreeInfo.symbol(tree.meth);
374 ClassSymbol c = (ClassSymbol)constructor.owner;
375 if (c.hasOuterInstance() &&
376 !tree.meth.hasTag(SELECT) &&
377 outerThisStack.head != null)
378 visitSymbol(outerThisStack.head);
379 }
380 super.visitApply(tree);
381 }
382
383 }
384
385 ClassSymbol ownerToCopyFreeVarsFrom(ClassSymbol c) {
386 if (!c.isLocal()) {
387 return null;
388 }
389 Symbol currentOwner = c.owner;
390 while (currentOwner.owner.kind.matches(KindSelector.TYP) && currentOwner.isLocal()) {
391 currentOwner = currentOwner.owner;
392 }
393 if (currentOwner.owner.kind.matches(KindSelector.VAL_MTH) && c.isSubClass(currentOwner, types)) {
394 return (ClassSymbol)currentOwner;
395 }
396 return null;
397 }
398
399 /** Return the variables accessed from within a local class, which
400 * are declared in the local class' owner.
401 * (in reverse order of first access).
402 */
3339 }
3340
3341 public void visitForLoop(JCForLoop tree) {
3342 tree.init = translate(tree.init);
3343 if (tree.cond != null)
3344 tree.cond = translate(tree.cond, syms.booleanType);
3345 tree.step = translate(tree.step);
3346 tree.body = translate(tree.body);
3347 result = tree;
3348 }
3349
3350 public void visitReturn(JCReturn tree) {
3351 if (tree.expr != null)
3352 tree.expr = translate(tree.expr,
3353 types.erasure(currentMethodDef
3354 .restype.type));
3355 result = tree;
3356 }
3357
3358 public void visitSwitch(JCSwitch tree) {
3359 //expand multiple label cases:
3360 ListBuffer<JCCase> cases = new ListBuffer<>();
3361
3362 for (JCCase c : tree.cases) {
3363 switch (c.pats.size()) {
3364 case 0: //default
3365 case 1: //single label
3366 cases.append(c);
3367 break;
3368 default: //multiple labels, expand:
3369 //case C1, C2, C3: ...
3370 //=>
3371 //case C1:
3372 //case C2:
3373 //case C3: ...
3374 List<JCExpression> patterns = c.pats;
3375 while (patterns.tail.nonEmpty()) {
3376 cases.append(make_at(c.pos()).Case(JCCase.STATEMENT,
3377 List.of(patterns.head),
3378 List.nil(),
3379 null));
3380 patterns = patterns.tail;
3381 }
3382 c.pats = patterns;
3383 cases.append(c);
3384 break;
3385 }
3386 }
3387
3388 for (JCCase c : cases) {
3389 if (c.caseKind == JCCase.RULE && c.completesNormally) {
3390 JCBreak b = make_at(c.pos()).Break(null);
3391 b.target = tree;
3392 c.stats = c.stats.append(b);
3393 }
3394 }
3395
3396 tree.cases = cases.toList();
3397
3398 Type selsuper = types.supertype(tree.selector.type);
3399 boolean enumSwitch = selsuper != null &&
3400 (tree.selector.type.tsym.flags() & ENUM) != 0;
3401 boolean stringSwitch = selsuper != null &&
3402 types.isSameType(tree.selector.type, syms.stringType);
3403 Type target = enumSwitch ? tree.selector.type :
3404 (stringSwitch? syms.stringType : syms.intType);
3405 tree.selector = translate(tree.selector, target);
3406 tree.cases = translateCases(tree.cases);
3407 if (enumSwitch) {
3408 result = visitEnumSwitch(tree);
3409 } else if (stringSwitch) {
3410 result = visitStringSwitch(tree);
3411 } else {
3412 result = tree;
3413 }
3414 }
3415
3416 public JCTree visitEnumSwitch(JCSwitch tree) {
3417 TypeSymbol enumSym = tree.selector.type.tsym;
3418 EnumMapping map = mapForEnum(tree.pos(), enumSym);
3419 make_at(tree.pos());
3420 Symbol ordinalMethod = lookupMethod(tree.pos(),
3421 names.ordinal,
3422 tree.selector.type,
3423 List.nil());
3424 JCArrayAccess selector = make.Indexed(map.mapVar,
3425 make.App(make.Select(tree.selector,
3426 ordinalMethod)));
3427 ListBuffer<JCCase> cases = new ListBuffer<>();
3428 for (JCCase c : tree.cases) {
3429 if (c.pats.nonEmpty()) {
3430 VarSymbol label = (VarSymbol)TreeInfo.symbol(c.pats.head);
3431 JCLiteral pat = map.forConstant(label);
3432 cases.append(make.Case(JCCase.STATEMENT, List.of(pat), c.stats, null));
3433 } else {
3434 cases.append(c);
3435 }
3436 }
3437 JCSwitch enumSwitch = make.Switch(selector, cases.toList());
3438 patchTargets(enumSwitch, tree, enumSwitch);
3439 return enumSwitch;
3440 }
3441
3442 public JCTree visitStringSwitch(JCSwitch tree) {
3443 List<JCCase> caseList = tree.getCases();
3444 int alternatives = caseList.size();
3445
3446 if (alternatives == 0) { // Strange but legal possibility
3447 return make.at(tree.pos()).Exec(attr.makeNullCheck(tree.getExpression()));
3448 } else {
3449 /*
3450 * The general approach used is to translate a single
3451 * string switch statement into a series of two chained
3452 * switch statements: the first a synthesized statement
3480 * since at least JDK 1.2. Since the algorithm has been
3481 * specified since that release as well, it is very
3482 * unlikely to be changed in the future.
3483 *
3484 * Different hashing algorithms, such as the length of the
3485 * strings or a perfect hashing algorithm over the
3486 * particular set of case labels, could potentially be
3487 * used instead of String.hashCode.
3488 */
3489
3490 ListBuffer<JCStatement> stmtList = new ListBuffer<>();
3491
3492 // Map from String case labels to their original position in
3493 // the list of case labels.
3494 Map<String, Integer> caseLabelToPosition = new LinkedHashMap<>(alternatives + 1, 1.0f);
3495
3496 // Map of hash codes to the string case labels having that hashCode.
3497 Map<Integer, Set<String>> hashToString = new LinkedHashMap<>(alternatives + 1, 1.0f);
3498
3499 int casePosition = 0;
3500
3501 for(JCCase oneCase : caseList) {
3502 if (oneCase.pats.nonEmpty()) { // pats is empty for a "default" case
3503 JCExpression expression = oneCase.pats.head;
3504 String labelExpr = (String) expression.type.constValue();
3505 Integer mapping = caseLabelToPosition.put(labelExpr, casePosition);
3506 Assert.checkNull(mapping);
3507 int hashCode = labelExpr.hashCode();
3508
3509 Set<String> stringSet = hashToString.get(hashCode);
3510 if (stringSet == null) {
3511 stringSet = new LinkedHashSet<>(1, 1.0f);
3512 stringSet.add(labelExpr);
3513 hashToString.put(hashCode, stringSet);
3514 } else {
3515 boolean added = stringSet.add(labelExpr);
3516 Assert.check(added);
3517 }
3518 }
3519 casePosition++;
3520 }
3521
3522 // Synthesize a switch statement that has the effect of
3523 // mapping from a string to the integer position of that
3567 Set<String> stringsWithHashCode = entry.getValue();
3568 Assert.check(stringsWithHashCode.size() >= 1);
3569
3570 JCStatement elsepart = null;
3571 for(String caseLabel : stringsWithHashCode ) {
3572 JCMethodInvocation stringEqualsCall = makeCall(make.Ident(dollar_s),
3573 names.equals,
3574 List.of(make.Literal(caseLabel)));
3575 elsepart = make.If(stringEqualsCall,
3576 make.Exec(make.Assign(make.Ident(dollar_tmp),
3577 make.Literal(caseLabelToPosition.get(caseLabel))).
3578 setType(dollar_tmp.type)),
3579 elsepart);
3580 }
3581
3582 ListBuffer<JCStatement> lb = new ListBuffer<>();
3583 JCBreak breakStmt = make.Break(null);
3584 breakStmt.target = switch1;
3585 lb.append(elsepart).append(breakStmt);
3586
3587 caseBuffer.append(make.Case(JCCase.STATEMENT, List.of(make.Literal(hashCode)), lb.toList(), null));
3588 }
3589
3590 switch1.cases = caseBuffer.toList();
3591 stmtList.append(switch1);
3592
3593 // Make isomorphic switch tree replacing string labels
3594 // with corresponding integer ones from the label to
3595 // position map.
3596
3597 ListBuffer<JCCase> lb = new ListBuffer<>();
3598 JCSwitch switch2 = make.Switch(make.Ident(dollar_tmp), lb.toList());
3599 for(JCCase oneCase : caseList ) {
3600 // Rewire up old unlabeled break statements to the
3601 // replacement switch being created.
3602 patchTargets(oneCase, tree, switch2);
3603
3604 boolean isDefault = (oneCase.pats.isEmpty());
3605 JCExpression caseExpr;
3606 if (isDefault)
3607 caseExpr = null;
3608 else {
3609 caseExpr = make.Literal(caseLabelToPosition.get((String)TreeInfo.skipParens(oneCase.pats.head).
3610 type.constValue()));
3611 }
3612
3613 lb.append(make.Case(JCCase.STATEMENT, caseExpr == null ? List.nil() : List.of(caseExpr),
3614 oneCase.getStatements(), null));
3615 }
3616
3617 switch2.cases = lb.toList();
3618 stmtList.append(switch2);
3619
3620 return make.Block(0L, stmtList.toList());
3621 }
3622 }
3623
3624 @Override
3625 public void visitSwitchExpression(JCSwitchExpression tree) {
3626 //translates switch expression to statement switch:
3627 //switch (selector) {
3628 // case C: break value;
3629 // ...
3630 //}
3631 //=>
3632 //(letexpr T exprswitch$;
3633 // switch (selector) {
3634 // case C: { exprswitch$ = value; break; }
3635 // }
3636 // exprswitch$
3637 //)
3638 VarSymbol dollar_switchexpr = new VarSymbol(Flags.FINAL|Flags.SYNTHETIC,
3639 names.fromString("exprswitch" + tree.pos + target.syntheticNameChar()),
3640 tree.type,
3641 currentMethodSym);
3642
3643 ListBuffer<JCStatement> stmtList = new ListBuffer<>();
3644
3645 stmtList.append(make.at(tree.pos()).VarDef(dollar_switchexpr, null).setType(dollar_switchexpr.type));
3646 JCSwitch switchStatement = make.Switch(tree.selector, null);
3647 switchStatement.cases =
3648 tree.cases.stream()
3649 .map(c -> convertCase(dollar_switchexpr, switchStatement, tree, c))
3650 .collect(List.collector());
3651 if (tree.cases.stream().noneMatch(c -> c.pats.isEmpty())) {
3652 JCThrow thr = make.Throw(makeNewClass(syms.incompatibleClassChangeErrorType,
3653 List.nil()));
3654 JCCase c = make.Case(JCCase.STATEMENT, List.nil(), List.of(thr), null);
3655 switchStatement.cases = switchStatement.cases.append(c);
3656 }
3657
3658 stmtList.append(translate(switchStatement));
3659
3660 result = make.LetExpr(stmtList.toList(), make.Ident(dollar_switchexpr))
3661 .setType(dollar_switchexpr.type);
3662 }
3663 //where:
3664 private JCCase convertCase(VarSymbol dollar_switchexpr, JCSwitch switchStatement,
3665 JCSwitchExpression switchExpr, JCCase c) {
3666 make.at(c.pos());
3667 ListBuffer<JCStatement> statements = new ListBuffer<>();
3668 statements.addAll(new TreeTranslator() {
3669 @Override
3670 public void visitLambda(JCLambda tree) {}
3671 @Override
3672 public void visitClassDef(JCClassDecl tree) {}
3673 @Override
3674 public void visitMethodDef(JCMethodDecl tree) {}
3675 @Override
3676 public void visitBreak(JCBreak tree) {
3677 if (tree.target == switchExpr) {
3678 tree.target = switchStatement;
3679 JCExpressionStatement assignment =
3680 make.Exec(make.Assign(make.Ident(dollar_switchexpr),
3681 translate(tree.value))
3682 .setType(dollar_switchexpr.type));
3683 result = make.Block(0, List.of(assignment,
3684 tree));
3685 tree.value = null;
3686 } else {
3687 result = tree;
3688 }
3689 }
3690 }.translate(c.stats));
3691 return make.Case(JCCase.STATEMENT, c.pats, statements.toList(), null);
3692 }
3693
3694 public void visitNewArray(JCNewArray tree) {
3695 tree.elemtype = translate(tree.elemtype);
3696 for (List<JCExpression> t = tree.dims; t.tail != null; t = t.tail)
3697 if (t.head != null) t.head = translate(t.head, syms.intType);
3698 tree.elems = translate(tree.elems, types.elemtype(tree.type));
3699 result = tree;
3700 }
3701
3702 public void visitSelect(JCFieldAccess tree) {
3703 // need to special case-access of the form C.super.x
3704 // these will always need an access method, unless C
3705 // is a default interface subclassed by the current class.
3706 boolean qualifiedSuperAccess =
3707 tree.selected.hasTag(SELECT) &&
3708 TreeInfo.name(tree.selected) == names._super &&
3709 !types.isDirectSuperInterface(((JCFieldAccess)tree.selected).selected.type.tsym, currentClass);
3710 tree.selected = translate(tree.selected);
3711 if (tree.name == names._class) {
3712 result = classOf(tree.selected);
3713 }
3714 else if (tree.name == names._super &&
3715 types.isDirectSuperInterface(tree.selected.type.tsym, currentClass)) {
3716 //default super call!! Not a classic qualified super call
3717 TypeSymbol supSym = tree.selected.type.tsym;
3718 Assert.checkNonNull(types.asSuper(currentClass.type, supSym));
3719 result = tree;
3720 }
3721 else if (tree.name == names._this || tree.name == names._super) {
3722 result = makeThis(tree.pos(), tree.selected.type.tsym);
3723 }
3724 else
3725 result = access(tree.sym, tree, enclOp, qualifiedSuperAccess);
3726 }
3727
3728 public void visitLetExpr(LetExpr tree) {
3729 tree.defs = translate(tree.defs);
3730 tree.expr = translate(tree.expr, tree.type);
3731 result = tree;
3732 }
3733
3734 // There ought to be nothing to rewrite here;
3735 // we don't generate code.
3736 public void visitAnnotation(JCAnnotation tree) {
3737 result = tree;
3738 }
3739
3740 @Override
3741 public void visitTry(JCTry tree) {
3742 if (tree.resources.nonEmpty()) {
3743 result = makeTwrTry(tree);
3744 return;
3745 }
3746
3747 boolean hasBody = tree.body.getStatements().nonEmpty();
3748 boolean hasCatchers = tree.catchers.nonEmpty();
3749 boolean hasFinally = tree.finalizer != null &&
|