73 // The set of lint options currently in effect. It is initialized |
73 // The set of lint options currently in effect. It is initialized |
74 // from the context, and then is set/reset as needed by Attr as it |
74 // from the context, and then is set/reset as needed by Attr as it |
75 // visits all the various parts of the trees during attribution. |
75 // visits all the various parts of the trees during attribution. |
76 private Lint lint; |
76 private Lint lint; |
77 |
77 |
|
78 // The method being analyzed in Attr - it is set/reset as needed by |
|
79 // Attr as it visits new method declarations. |
|
80 private MethodSymbol method; |
|
81 |
78 public static Check instance(Context context) { |
82 public static Check instance(Context context) { |
79 Check instance = context.get(checkKey); |
83 Check instance = context.get(checkKey); |
80 if (instance == null) |
84 if (instance == null) |
81 instance = new Check(context); |
85 instance = new Check(context); |
82 return instance; |
86 return instance; |
98 |
102 |
99 Source source = Source.instance(context); |
103 Source source = Source.instance(context); |
100 allowGenerics = source.allowGenerics(); |
104 allowGenerics = source.allowGenerics(); |
101 allowAnnotations = source.allowAnnotations(); |
105 allowAnnotations = source.allowAnnotations(); |
102 allowCovariantReturns = source.allowCovariantReturns(); |
106 allowCovariantReturns = source.allowCovariantReturns(); |
|
107 allowSimplifiedVarargs = source.allowSimplifiedVarargs(); |
103 complexInference = options.isSet(COMPLEXINFERENCE); |
108 complexInference = options.isSet(COMPLEXINFERENCE); |
104 skipAnnotations = options.isSet("skipAnnotations"); |
109 skipAnnotations = options.isSet("skipAnnotations"); |
105 warnOnSyntheticConflicts = options.isSet("warnOnSyntheticConflicts"); |
110 warnOnSyntheticConflicts = options.isSet("warnOnSyntheticConflicts"); |
106 suppressAbortOnBadClassFile = options.isSet("suppressAbortOnBadClassFile"); |
111 suppressAbortOnBadClassFile = options.isSet("suppressAbortOnBadClassFile"); |
107 |
112 |
195 |
210 |
196 /** Warn about unsafe vararg method decl. |
211 /** Warn about unsafe vararg method decl. |
197 * @param pos Position to be used for error reporting. |
212 * @param pos Position to be used for error reporting. |
198 * @param sym The deprecated symbol. |
213 * @param sym The deprecated symbol. |
199 */ |
214 */ |
200 void warnUnsafeVararg(DiagnosticPosition pos, Type elemType) { |
215 void warnUnsafeVararg(DiagnosticPosition pos, String key, Object... args) { |
201 if (!lint.isSuppressed(LintCategory.VARARGS)) |
216 if (lint.isEnabled(LintCategory.VARARGS) && allowSimplifiedVarargs) |
202 unsafeVarargsHandler.report(pos, "varargs.non.reifiable.type", elemType); |
217 log.warning(LintCategory.VARARGS, pos, key, args); |
203 } |
218 } |
204 |
219 |
205 /** Warn about using proprietary API. |
220 /** Warn about using proprietary API. |
206 * @param pos Position to be used for error reporting. |
221 * @param pos Position to be used for error reporting. |
207 * @param msg A string describing the problem. |
222 * @param msg A string describing the problem. |
703 public Boolean visitCapturedType(CapturedType t, Void s) { |
717 public Boolean visitCapturedType(CapturedType t, Void s) { |
704 return false; |
718 return false; |
705 } |
719 } |
706 } |
720 } |
707 |
721 |
708 void checkVarargMethodDecl(JCMethodDecl tree) { |
722 void checkVarargsMethodDecl(Env<AttrContext> env, JCMethodDecl tree) { |
709 MethodSymbol m = tree.sym; |
723 MethodSymbol m = tree.sym; |
710 //check the element type of the vararg |
724 if (!allowSimplifiedVarargs) return; |
|
725 boolean hasTrustMeAnno = m.attribute(syms.trustMeType.tsym) != null; |
|
726 Type varargElemType = null; |
711 if (m.isVarArgs()) { |
727 if (m.isVarArgs()) { |
712 Type varargElemType = types.elemtype(tree.params.last().type); |
728 varargElemType = types.elemtype(tree.params.last().type); |
713 if (!types.isReifiable(varargElemType)) { |
729 } |
714 warnUnsafeVararg(tree.params.head.pos(), varargElemType); |
730 if (hasTrustMeAnno && !isTrustMeAllowedOnMethod(m)) { |
715 } |
731 if (varargElemType != null) { |
716 } |
732 log.error(tree, |
717 } |
733 "varargs.invalid.trustme.anno", |
|
734 syms.trustMeType.tsym, |
|
735 diags.fragment("varargs.trustme.on.virtual.varargs", m)); |
|
736 } else { |
|
737 log.error(tree, |
|
738 "varargs.invalid.trustme.anno", |
|
739 syms.trustMeType.tsym, |
|
740 diags.fragment("varargs.trustme.on.non.varargs.meth", m)); |
|
741 } |
|
742 } else if (hasTrustMeAnno && varargElemType != null && |
|
743 types.isReifiable(varargElemType)) { |
|
744 warnUnsafeVararg(tree, |
|
745 "varargs.redundant.trustme.anno", |
|
746 syms.trustMeType.tsym, |
|
747 diags.fragment("varargs.trustme.on.reifiable.varargs", varargElemType)); |
|
748 } |
|
749 else if (!hasTrustMeAnno && varargElemType != null && |
|
750 !types.isReifiable(varargElemType)) { |
|
751 warnUnchecked(tree.params.head.pos(), "unchecked.varargs.non.reifiable.type", varargElemType); |
|
752 } |
|
753 } |
|
754 //where |
|
755 private boolean isTrustMeAllowedOnMethod(Symbol s) { |
|
756 return (s.flags() & VARARGS) != 0 && |
|
757 (s.isConstructor() || |
|
758 (s.flags() & (STATIC | FINAL)) != 0); |
|
759 } |
718 |
760 |
719 /** |
761 /** |
720 * Check that vararg method call is sound |
762 * Check that vararg method call is sound |
721 * @param pos Position to be used for error reporting. |
763 * @param pos Position to be used for error reporting. |
722 * @param argtypes Actual arguments supplied to vararg method. |
764 * @param argtypes Actual arguments supplied to vararg method. |
723 */ |
765 */ |
724 void checkVararg(DiagnosticPosition pos, List<Type> argtypes, Symbol msym, Env<AttrContext> env) { |
766 void checkVararg(DiagnosticPosition pos, List<Type> argtypes, Symbol msym) { |
725 Env<AttrContext> calleeLintEnv = env; |
|
726 while (calleeLintEnv.info.lint == null) |
|
727 calleeLintEnv = calleeLintEnv.next; |
|
728 Lint calleeLint = calleeLintEnv.info.lint.augment(msym.attributes_field, msym.flags()); |
|
729 Type argtype = argtypes.last(); |
767 Type argtype = argtypes.last(); |
730 if (!types.isReifiable(argtype) && !calleeLint.isSuppressed(Lint.LintCategory.VARARGS)) { |
768 if (!types.isReifiable(argtype) && |
|
769 (!allowSimplifiedVarargs || |
|
770 msym.attribute(syms.trustMeType.tsym) == null || |
|
771 !isTrustMeAllowedOnMethod(msym))) { |
731 warnUnchecked(pos, |
772 warnUnchecked(pos, |
732 "unchecked.generic.array.creation", |
773 "unchecked.generic.array.creation", |
733 argtype); |
774 argtype); |
734 } |
775 } |
735 } |
776 } |
1073 for (List<? extends JCTree> l = trees; l.nonEmpty(); l = l.tail) |
1114 for (List<? extends JCTree> l = trees; l.nonEmpty(); l = l.tail) |
1074 validateTree(l.head, checkRaw, isOuter); |
1115 validateTree(l.head, checkRaw, isOuter); |
1075 } |
1116 } |
1076 |
1117 |
1077 void checkRaw(JCTree tree, Env<AttrContext> env) { |
1118 void checkRaw(JCTree tree, Env<AttrContext> env) { |
1078 if (lint.isEnabled(Lint.LintCategory.RAW) && |
1119 if (lint.isEnabled(LintCategory.RAW) && |
1079 tree.type.tag == CLASS && |
1120 tree.type.tag == CLASS && |
1080 !TreeInfo.isDiamond(tree) && |
1121 !TreeInfo.isDiamond(tree) && |
1081 !env.enclClass.name.isEmpty() && //anonymous or intersection |
1122 !env.enclClass.name.isEmpty() && //anonymous or intersection |
1082 tree.type.isRaw()) { |
1123 tree.type.isRaw()) { |
1083 log.warning(Lint.LintCategory.RAW, |
1124 log.warning(LintCategory.RAW, |
1084 tree.pos(), "raw.class.use", tree.type, tree.type.tsym.type); |
1125 tree.pos(), "raw.class.use", tree.type, tree.type.tsym.type); |
1085 } |
1126 } |
1086 } |
1127 } |
1087 } |
1128 } |
1088 |
1129 |
1345 List<Type> mtvars = mt.getTypeArguments(); |
1386 List<Type> mtvars = mt.getTypeArguments(); |
1346 List<Type> otvars = ot.getTypeArguments(); |
1387 List<Type> otvars = ot.getTypeArguments(); |
1347 Type mtres = mt.getReturnType(); |
1388 Type mtres = mt.getReturnType(); |
1348 Type otres = types.subst(ot.getReturnType(), otvars, mtvars); |
1389 Type otres = types.subst(ot.getReturnType(), otvars, mtvars); |
1349 |
1390 |
1350 overrideWarner.warned = false; |
1391 overrideWarner.clear(); |
1351 boolean resultTypesOK = |
1392 boolean resultTypesOK = |
1352 types.returnTypeSubstitutable(mt, ot, otres, overrideWarner); |
1393 types.returnTypeSubstitutable(mt, ot, otres, overrideWarner); |
1353 if (!resultTypesOK) { |
1394 if (!resultTypesOK) { |
1354 if (!allowCovariantReturns && |
1395 if (!allowCovariantReturns && |
1355 m.owner != origin && |
1396 m.owner != origin && |
1360 "override.incompatible.ret", |
1401 "override.incompatible.ret", |
1361 cannotOverride(m, other), |
1402 cannotOverride(m, other), |
1362 mtres, otres); |
1403 mtres, otres); |
1363 return; |
1404 return; |
1364 } |
1405 } |
1365 } else if (overrideWarner.warned) { |
1406 } else if (overrideWarner.hasNonSilentLint(LintCategory.UNCHECKED)) { |
1366 warnUnchecked(TreeInfo.diagnosticPositionFor(m, tree), |
1407 warnUnchecked(TreeInfo.diagnosticPositionFor(m, tree), |
1367 "override.unchecked.ret", |
1408 "override.unchecked.ret", |
1368 uncheckedOverrides(m, other), |
1409 uncheckedOverrides(m, other), |
1369 mtres, otres); |
1410 mtres, otres); |
1370 } |
1411 } |
1389 return; |
1430 return; |
1390 } |
1431 } |
1391 |
1432 |
1392 // Optional warning if varargs don't agree |
1433 // Optional warning if varargs don't agree |
1393 if ((((m.flags() ^ other.flags()) & Flags.VARARGS) != 0) |
1434 if ((((m.flags() ^ other.flags()) & Flags.VARARGS) != 0) |
1394 && lint.isEnabled(Lint.LintCategory.OVERRIDES)) { |
1435 && lint.isEnabled(LintCategory.OVERRIDES)) { |
1395 log.warning(TreeInfo.diagnosticPositionFor(m, tree), |
1436 log.warning(TreeInfo.diagnosticPositionFor(m, tree), |
1396 ((m.flags() & Flags.VARARGS) != 0) |
1437 ((m.flags() & Flags.VARARGS) != 0) |
1397 ? "override.varargs.missing" |
1438 ? "override.varargs.missing" |
1398 : "override.varargs.extra", |
1439 : "override.varargs.extra", |
1399 varargsOverrides(m, other)); |
1440 varargsOverrides(m, other)); |
2378 } |
2419 } |
2379 } |
2420 } |
2380 |
2421 |
2381 void checkDeprecatedAnnotation(DiagnosticPosition pos, Symbol s) { |
2422 void checkDeprecatedAnnotation(DiagnosticPosition pos, Symbol s) { |
2382 if (allowAnnotations && |
2423 if (allowAnnotations && |
2383 lint.isEnabled(Lint.LintCategory.DEP_ANN) && |
2424 lint.isEnabled(LintCategory.DEP_ANN) && |
2384 (s.flags() & DEPRECATED) != 0 && |
2425 (s.flags() & DEPRECATED) != 0 && |
2385 !syms.deprecatedType.isErroneous() && |
2426 !syms.deprecatedType.isErroneous() && |
2386 s.attribute(syms.deprecatedType.tsym) == null) { |
2427 s.attribute(syms.deprecatedType.tsym) == null) { |
2387 log.warning(Lint.LintCategory.DEP_ANN, |
2428 log.warning(LintCategory.DEP_ANN, |
2388 pos, "missing.deprecated.annotation"); |
2429 pos, "missing.deprecated.annotation"); |
2389 } |
2430 } |
2390 } |
2431 } |
2391 |
2432 |
2392 /* ************************************************************************* |
2433 /* ************************************************************************* |
2528 * @param operator The operator for the expression |
2569 * @param operator The operator for the expression |
2529 * @param operand The right hand operand for the expression |
2570 * @param operand The right hand operand for the expression |
2530 */ |
2571 */ |
2531 void checkDivZero(DiagnosticPosition pos, Symbol operator, Type operand) { |
2572 void checkDivZero(DiagnosticPosition pos, Symbol operator, Type operand) { |
2532 if (operand.constValue() != null |
2573 if (operand.constValue() != null |
2533 && lint.isEnabled(Lint.LintCategory.DIVZERO) |
2574 && lint.isEnabled(LintCategory.DIVZERO) |
2534 && operand.tag <= LONG |
2575 && operand.tag <= LONG |
2535 && ((Number) (operand.constValue())).longValue() == 0) { |
2576 && ((Number) (operand.constValue())).longValue() == 0) { |
2536 int opc = ((OperatorSymbol)operator).opcode; |
2577 int opc = ((OperatorSymbol)operator).opcode; |
2537 if (opc == ByteCodes.idiv || opc == ByteCodes.imod |
2578 if (opc == ByteCodes.idiv || opc == ByteCodes.imod |
2538 || opc == ByteCodes.ldiv || opc == ByteCodes.lmod) { |
2579 || opc == ByteCodes.ldiv || opc == ByteCodes.lmod) { |
2539 log.warning(Lint.LintCategory.DIVZERO, pos, "div.zero"); |
2580 log.warning(LintCategory.DIVZERO, pos, "div.zero"); |
2540 } |
2581 } |
2541 } |
2582 } |
2542 } |
2583 } |
2543 |
2584 |
2544 /** |
2585 /** |
2545 * Check for empty statements after if |
2586 * Check for empty statements after if |
2546 */ |
2587 */ |
2547 void checkEmptyIf(JCIf tree) { |
2588 void checkEmptyIf(JCIf tree) { |
2548 if (tree.thenpart.getTag() == JCTree.SKIP && tree.elsepart == null && lint.isEnabled(Lint.LintCategory.EMPTY)) |
2589 if (tree.thenpart.getTag() == JCTree.SKIP && tree.elsepart == null && lint.isEnabled(LintCategory.EMPTY)) |
2549 log.warning(Lint.LintCategory.EMPTY, tree.thenpart.pos(), "empty.if"); |
2590 log.warning(LintCategory.EMPTY, tree.thenpart.pos(), "empty.if"); |
2550 } |
2591 } |
2551 |
2592 |
2552 /** Check that symbol is unique in given scope. |
2593 /** Check that symbol is unique in given scope. |
2553 * @param pos Position for error reporting. |
2594 * @param pos Position for error reporting. |
2554 * @param sym The symbol. |
2595 * @param sym The symbol. |
2652 } |
2693 } |
2653 return true; |
2694 return true; |
2654 } |
2695 } |
2655 |
2696 |
2656 private class ConversionWarner extends Warner { |
2697 private class ConversionWarner extends Warner { |
2657 final String key; |
2698 final String uncheckedKey; |
2658 final Type found; |
2699 final Type found; |
2659 final Type expected; |
2700 final Type expected; |
2660 public ConversionWarner(DiagnosticPosition pos, String key, Type found, Type expected) { |
2701 public ConversionWarner(DiagnosticPosition pos, String uncheckedKey, Type found, Type expected) { |
2661 super(pos); |
2702 super(pos); |
2662 this.key = key; |
2703 this.uncheckedKey = uncheckedKey; |
2663 this.found = found; |
2704 this.found = found; |
2664 this.expected = expected; |
2705 this.expected = expected; |
2665 } |
2706 } |
2666 |
2707 |
2667 @Override |
2708 @Override |
2668 public void warnUnchecked() { |
2709 public void warn(LintCategory lint) { |
2669 boolean warned = this.warned; |
2710 boolean warned = this.warned; |
2670 super.warnUnchecked(); |
2711 super.warn(lint); |
2671 if (warned) return; // suppress redundant diagnostics |
2712 if (warned) return; // suppress redundant diagnostics |
2672 Object problem = diags.fragment(key); |
2713 switch (lint) { |
2673 Check.this.warnUnchecked(pos(), "prob.found.req", problem, found, expected); |
2714 case UNCHECKED: |
|
2715 Check.this.warnUnchecked(pos(), "prob.found.req", diags.fragment(uncheckedKey), found, expected); |
|
2716 break; |
|
2717 case VARARGS: |
|
2718 if (method != null && |
|
2719 method.attribute(syms.trustMeType.tsym) != null && |
|
2720 isTrustMeAllowedOnMethod(method) && |
|
2721 !types.isReifiable(method.type.getParameterTypes().last())) { |
|
2722 Check.this.warnUnsafeVararg(pos(), "varargs.unsafe.use.varargs.param", method.params.last()); |
|
2723 } |
|
2724 break; |
|
2725 default: |
|
2726 throw new AssertionError("Unexpected lint: " + lint); |
|
2727 } |
2674 } |
2728 } |
2675 } |
2729 } |
2676 |
2730 |
2677 public Warner castWarner(DiagnosticPosition pos, Type found, Type expected) { |
2731 public Warner castWarner(DiagnosticPosition pos, Type found, Type expected) { |
2678 return new ConversionWarner(pos, "unchecked.cast.to.type", found, expected); |
2732 return new ConversionWarner(pos, "unchecked.cast.to.type", found, expected); |