30 import java.util.HashMap; |
30 import java.util.HashMap; |
31 |
31 |
32 import com.sun.source.tree.LambdaExpressionTree.BodyKind; |
32 import com.sun.source.tree.LambdaExpressionTree.BodyKind; |
33 import com.sun.tools.javac.code.*; |
33 import com.sun.tools.javac.code.*; |
34 import com.sun.tools.javac.code.Scope.WriteableScope; |
34 import com.sun.tools.javac.code.Scope.WriteableScope; |
|
35 import com.sun.tools.javac.resources.CompilerProperties.Errors; |
|
36 import com.sun.tools.javac.resources.CompilerProperties.Warnings; |
35 import com.sun.tools.javac.tree.*; |
37 import com.sun.tools.javac.tree.*; |
36 import com.sun.tools.javac.util.*; |
38 import com.sun.tools.javac.util.*; |
37 import com.sun.tools.javac.util.JCDiagnostic.DiagnosticPosition; |
39 import com.sun.tools.javac.util.JCDiagnostic.DiagnosticPosition; |
38 |
40 |
39 import com.sun.tools.javac.code.Symbol.*; |
41 import com.sun.tools.javac.code.Symbol.*; |
425 */ |
427 */ |
426 void scanDef(JCTree tree) { |
428 void scanDef(JCTree tree) { |
427 scanStat(tree); |
429 scanStat(tree); |
428 if (tree != null && tree.hasTag(JCTree.Tag.BLOCK) && !alive) { |
430 if (tree != null && tree.hasTag(JCTree.Tag.BLOCK) && !alive) { |
429 log.error(tree.pos(), |
431 log.error(tree.pos(), |
430 "initializer.must.be.able.to.complete.normally"); |
432 Errors.InitializerMustBeAbleToCompleteNormally); |
431 } |
433 } |
432 } |
434 } |
433 |
435 |
434 /** Analyze a statement. Check that statement is reachable. |
436 /** Analyze a statement. Check that statement is reachable. |
435 */ |
437 */ |
436 void scanStat(JCTree tree) { |
438 void scanStat(JCTree tree) { |
437 if (!alive && tree != null) { |
439 if (!alive && tree != null) { |
438 log.error(tree.pos(), "unreachable.stmt"); |
440 log.error(tree.pos(), Errors.UnreachableStmt); |
439 if (!tree.hasTag(SKIP)) alive = true; |
441 if (!tree.hasTag(SKIP)) alive = true; |
440 } |
442 } |
441 scan(tree); |
443 scan(tree); |
442 } |
444 } |
443 |
445 |
501 try { |
503 try { |
502 alive = true; |
504 alive = true; |
503 scanStat(tree.body); |
505 scanStat(tree.body); |
504 |
506 |
505 if (alive && !tree.sym.type.getReturnType().hasTag(VOID)) |
507 if (alive && !tree.sym.type.getReturnType().hasTag(VOID)) |
506 log.error(TreeInfo.diagEndPos(tree.body), "missing.ret.stmt"); |
508 log.error(TreeInfo.diagEndPos(tree.body), Errors.MissingRetStmt); |
507 |
509 |
508 List<PendingExit> exits = pendingExits.toList(); |
510 List<PendingExit> exits = pendingExits.toList(); |
509 pendingExits = new ListBuffer<>(); |
511 pendingExits = new ListBuffer<>(); |
510 while (exits.nonEmpty()) { |
512 while (exits.nonEmpty()) { |
511 PendingExit exit = exits.head; |
513 PendingExit exit = exits.head; |
606 if (alive && |
608 if (alive && |
607 lint.isEnabled(Lint.LintCategory.FALLTHROUGH) && |
609 lint.isEnabled(Lint.LintCategory.FALLTHROUGH) && |
608 c.stats.nonEmpty() && l.tail.nonEmpty()) |
610 c.stats.nonEmpty() && l.tail.nonEmpty()) |
609 log.warning(Lint.LintCategory.FALLTHROUGH, |
611 log.warning(Lint.LintCategory.FALLTHROUGH, |
610 l.tail.head.pos(), |
612 l.tail.head.pos(), |
611 "possible.fall-through.into.case"); |
613 Warnings.PossibleFallThroughIntoCase); |
612 } |
614 } |
613 if (!hasDefault) { |
615 if (!hasDefault) { |
614 alive = true; |
616 alive = true; |
615 } |
617 } |
616 alive |= resolveBreaks(tree, prevPendingExits); |
618 alive |= resolveBreaks(tree, prevPendingExits); |
648 tree.finallyCanCompleteNormally = alive; |
650 tree.finallyCanCompleteNormally = alive; |
649 if (!alive) { |
651 if (!alive) { |
650 if (lint.isEnabled(Lint.LintCategory.FINALLY)) { |
652 if (lint.isEnabled(Lint.LintCategory.FINALLY)) { |
651 log.warning(Lint.LintCategory.FINALLY, |
653 log.warning(Lint.LintCategory.FINALLY, |
652 TreeInfo.diagEndPos(tree.finalizer), |
654 TreeInfo.diagEndPos(tree.finalizer), |
653 "finally.cannot.complete"); |
655 Warnings.FinallyCannotComplete); |
654 } |
656 } |
655 } else { |
657 } else { |
656 while (exits.nonEmpty()) { |
658 while (exits.nonEmpty()) { |
657 pendingExits.append(exits.next()); |
659 pendingExits.append(exits.next()); |
658 } |
660 } |
809 exit != null; |
811 exit != null; |
810 exit = pendingExits.next()) { |
812 exit = pendingExits.next()) { |
811 if (classDef != null && |
813 if (classDef != null && |
812 classDef.pos == exit.tree.pos) { |
814 classDef.pos == exit.tree.pos) { |
813 log.error(exit.tree.pos(), |
815 log.error(exit.tree.pos(), |
814 "unreported.exception.default.constructor", |
816 Errors.UnreportedExceptionDefaultConstructor(exit.thrown)); |
815 exit.thrown); |
|
816 } else if (exit.tree.hasTag(VARDEF) && |
817 } else if (exit.tree.hasTag(VARDEF) && |
817 ((JCVariableDecl)exit.tree).sym.isResourceVariable()) { |
818 ((JCVariableDecl)exit.tree).sym.isResourceVariable()) { |
818 log.error(exit.tree.pos(), |
819 log.error(exit.tree.pos(), |
819 "unreported.exception.implicit.close", |
820 Errors.UnreportedExceptionImplicitClose(exit.thrown, |
820 exit.thrown, |
821 ((JCVariableDecl)exit.tree).sym.name)); |
821 ((JCVariableDecl)exit.tree).sym.name); |
|
822 } else { |
822 } else { |
823 log.error(exit.tree.pos(), |
823 log.error(exit.tree.pos(), |
824 "unreported.exception.need.to.catch.or.throw", |
824 Errors.UnreportedExceptionNeedToCatchOrThrow(exit.thrown)); |
825 exit.thrown); |
|
826 } |
825 } |
827 } |
826 } |
828 } |
827 } |
829 |
828 |
830 /** Record that exception is potentially thrown and check that it |
829 /** Record that exception is potentially thrown and check that it |
1168 } |
1167 } |
1169 } |
1168 } |
1170 |
1169 |
1171 void checkCaughtType(DiagnosticPosition pos, Type exc, List<Type> thrownInTry, List<Type> caughtInTry) { |
1170 void checkCaughtType(DiagnosticPosition pos, Type exc, List<Type> thrownInTry, List<Type> caughtInTry) { |
1172 if (chk.subset(exc, caughtInTry)) { |
1171 if (chk.subset(exc, caughtInTry)) { |
1173 log.error(pos, "except.already.caught", exc); |
1172 log.error(pos, Errors.ExceptAlreadyCaught(exc)); |
1174 } else if (!chk.isUnchecked(pos, exc) && |
1173 } else if (!chk.isUnchecked(pos, exc) && |
1175 !isExceptionOrThrowable(exc) && |
1174 !isExceptionOrThrowable(exc) && |
1176 !chk.intersects(exc, thrownInTry)) { |
1175 !chk.intersects(exc, thrownInTry)) { |
1177 log.error(pos, "except.never.thrown.in.try", exc); |
1176 log.error(pos, Errors.ExceptNeverThrownInTry(exc)); |
1178 } else if (allowImprovedCatchAnalysis) { |
1177 } else if (allowImprovedCatchAnalysis) { |
1179 List<Type> catchableThrownTypes = chk.intersect(List.of(exc), thrownInTry); |
1178 List<Type> catchableThrownTypes = chk.intersect(List.of(exc), thrownInTry); |
1180 // 'catchableThrownTypes' cannnot possibly be empty - if 'exc' was an |
1179 // 'catchableThrownTypes' cannnot possibly be empty - if 'exc' was an |
1181 // unchecked exception, the result list would not be empty, as the augmented |
1180 // unchecked exception, the result list would not be empty, as the augmented |
1182 // thrown set includes { RuntimeException, Error }; if 'exc' was a checked |
1181 // thrown set includes { RuntimeException, Error }; if 'exc' was a checked |
1608 } |
1607 } |
1609 } |
1608 } |
1610 else if ((sym.flags() & FINAL) != 0) { |
1609 else if ((sym.flags() & FINAL) != 0) { |
1611 if ((sym.flags() & PARAMETER) != 0) { |
1610 if ((sym.flags() & PARAMETER) != 0) { |
1612 if ((sym.flags() & UNION) != 0) { //multi-catch parameter |
1611 if ((sym.flags() & UNION) != 0) { //multi-catch parameter |
1613 log.error(pos, "multicatch.parameter.may.not.be.assigned", sym); |
1612 log.error(pos, Errors.MulticatchParameterMayNotBeAssigned(sym)); |
1614 } |
1613 } |
1615 else { |
1614 else { |
1616 log.error(pos, "final.parameter.may.not.be.assigned", |
1615 log.error(pos, |
1617 sym); |
1616 Errors.FinalParameterMayNotBeAssigned(sym)); |
1618 } |
1617 } |
1619 } else if (!uninits.isMember(sym.adr)) { |
1618 } else if (!uninits.isMember(sym.adr)) { |
1620 log.error(pos, flowKind.errKey, sym); |
1619 log.error(pos, flowKind.errKey, sym); |
1621 } else { |
1620 } else { |
1622 uninit(sym); |
1621 uninit(sym); |
1623 } |
1622 } |
1624 } |
1623 } |
1625 inits.incl(sym.adr); |
1624 inits.incl(sym.adr); |
1626 } else if ((sym.flags() & FINAL) != 0) { |
1625 } else if ((sym.flags() & FINAL) != 0) { |
1627 log.error(pos, "var.might.already.be.assigned", sym); |
1626 log.error(pos, Errors.VarMightAlreadyBeAssigned(sym)); |
1628 } |
1627 } |
1629 } |
1628 } |
1630 //where |
1629 //where |
1631 void uninit(VarSymbol sym) { |
1630 void uninit(VarSymbol sym) { |
1632 if (!inits.isMember(sym.adr)) { |
1631 if (!inits.isMember(sym.adr)) { |
2188 if (!resourceVarDecls.isEmpty() && |
2187 if (!resourceVarDecls.isEmpty() && |
2189 lint.isEnabled(Lint.LintCategory.TRY)) { |
2188 lint.isEnabled(Lint.LintCategory.TRY)) { |
2190 for (JCVariableDecl resVar : resourceVarDecls) { |
2189 for (JCVariableDecl resVar : resourceVarDecls) { |
2191 if (unrefdResources.includes(resVar.sym)) { |
2190 if (unrefdResources.includes(resVar.sym)) { |
2192 log.warning(Lint.LintCategory.TRY, resVar.pos(), |
2191 log.warning(Lint.LintCategory.TRY, resVar.pos(), |
2193 "try.resource.not.referenced", resVar.sym); |
2192 Warnings.TryResourceNotReferenced(resVar.sym)); |
2194 unrefdResources.remove(resVar.sym); |
2193 unrefdResources.remove(resVar.sym); |
2195 } |
2194 } |
2196 } |
2195 } |
2197 } |
2196 } |
2198 |
2197 |
2599 } |
2598 } |
2600 |
2599 |
2601 void reportEffectivelyFinalError(DiagnosticPosition pos, Symbol sym) { |
2600 void reportEffectivelyFinalError(DiagnosticPosition pos, Symbol sym) { |
2602 String subKey = currentTree.hasTag(LAMBDA) ? |
2601 String subKey = currentTree.hasTag(LAMBDA) ? |
2603 "lambda" : "inner.cls"; |
2602 "lambda" : "inner.cls"; |
2604 log.error(pos, "cant.ref.non.effectively.final.var", sym, diags.fragment(subKey)); |
2603 log.error(pos, Errors.CantRefNonEffectivelyFinalVar(sym, diags.fragment(subKey))); |
2605 } |
2604 } |
2606 |
2605 |
2607 void reportInnerClsNeedsFinalError(DiagnosticPosition pos, Symbol sym) { |
2606 void reportInnerClsNeedsFinalError(DiagnosticPosition pos, Symbol sym) { |
2608 log.error(pos, |
2607 log.error(pos, |
2609 "local.var.accessed.from.icls.needs.final", |
2608 Errors.LocalVarAccessedFromIclsNeedsFinal(sym)); |
2610 sym); |
|
2611 } |
2609 } |
2612 |
2610 |
2613 /************************************************************************* |
2611 /************************************************************************* |
2614 * Visitor methods for statements and definitions |
2612 * Visitor methods for statements and definitions |
2615 *************************************************************************/ |
2613 *************************************************************************/ |
2674 public void visitTry(JCTry tree) { |
2672 public void visitTry(JCTry tree) { |
2675 for (JCTree resource : tree.resources) { |
2673 for (JCTree resource : tree.resources) { |
2676 if (!resource.hasTag(VARDEF)) { |
2674 if (!resource.hasTag(VARDEF)) { |
2677 Symbol var = TreeInfo.symbol(resource); |
2675 Symbol var = TreeInfo.symbol(resource); |
2678 if (var != null && (var.flags() & (FINAL | EFFECTIVELY_FINAL)) == 0) { |
2676 if (var != null && (var.flags() & (FINAL | EFFECTIVELY_FINAL)) == 0) { |
2679 log.error(resource.pos(), "try.with.resources.expr.effectively.final.var", var); |
2677 log.error(resource.pos(), Errors.TryWithResourcesExprEffectivelyFinalVar(var)); |
2680 } |
2678 } |
2681 } |
2679 } |
2682 } |
2680 } |
2683 super.visitTry(tree); |
2681 super.visitTry(tree); |
2684 } |
2682 } |