1 /* 2 * Copyright (c) 1999, 2025, 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 26 package com.sun.tools.javac.comp; 27 28 import java.util.*; 29 import java.util.function.BiConsumer; 30 import java.util.function.BiPredicate; 31 import java.util.function.Function; 32 import java.util.function.Predicate; 33 import java.util.function.Supplier; 34 import java.util.function.ToIntBiFunction; 35 import java.util.stream.Collectors; 36 import java.util.stream.StreamSupport; 37 38 import javax.lang.model.element.ElementKind; 39 import javax.lang.model.element.NestingKind; 40 import javax.tools.JavaFileManager; 41 42 import com.sun.source.tree.CaseTree; 43 import com.sun.tools.javac.code.*; 44 import com.sun.tools.javac.code.Attribute.Compound; 45 import com.sun.tools.javac.code.Directive.ExportsDirective; 46 import com.sun.tools.javac.code.Directive.RequiresDirective; 47 import com.sun.tools.javac.code.Source.Feature; 48 import com.sun.tools.javac.comp.Annotate.AnnotationTypeMetadata; 49 import com.sun.tools.javac.jvm.*; 50 import com.sun.tools.javac.resources.CompilerProperties; 51 import com.sun.tools.javac.resources.CompilerProperties.Errors; 52 import com.sun.tools.javac.resources.CompilerProperties.Fragments; 53 import com.sun.tools.javac.resources.CompilerProperties.Warnings; 54 import com.sun.tools.javac.resources.CompilerProperties.LintWarnings; 55 import com.sun.tools.javac.tree.*; 56 import com.sun.tools.javac.util.*; 57 import com.sun.tools.javac.util.JCDiagnostic.DiagnosticFlag; 58 import com.sun.tools.javac.util.JCDiagnostic.DiagnosticPosition; 59 import com.sun.tools.javac.util.JCDiagnostic.Error; 60 import com.sun.tools.javac.util.JCDiagnostic.Fragment; 61 import com.sun.tools.javac.util.JCDiagnostic.LintWarning; 62 import com.sun.tools.javac.util.List; 63 64 import com.sun.tools.javac.code.Lint; 65 import com.sun.tools.javac.code.Lint.LintCategory; 66 import com.sun.tools.javac.code.Scope.WriteableScope; 67 import com.sun.tools.javac.code.Type.*; 68 import com.sun.tools.javac.code.Symbol.*; 69 import com.sun.tools.javac.comp.DeferredAttr.DeferredAttrContext; 70 import com.sun.tools.javac.tree.JCTree.*; 71 72 import static com.sun.tools.javac.code.Flags.*; 73 import static com.sun.tools.javac.code.Flags.ANNOTATION; 74 import static com.sun.tools.javac.code.Flags.SYNCHRONIZED; 75 import static com.sun.tools.javac.code.Kinds.*; 76 import static com.sun.tools.javac.code.Kinds.Kind.*; 77 import static com.sun.tools.javac.code.Scope.LookupKind.NON_RECURSIVE; 78 import static com.sun.tools.javac.code.Scope.LookupKind.RECURSIVE; 79 import static com.sun.tools.javac.code.TypeTag.*; 80 import static com.sun.tools.javac.code.TypeTag.WILDCARD; 81 82 import static com.sun.tools.javac.tree.JCTree.Tag.*; 83 import javax.lang.model.element.Element; 84 import javax.lang.model.element.TypeElement; 85 import javax.lang.model.type.DeclaredType; 86 import javax.lang.model.util.ElementKindVisitor14; 87 88 /** Type checking helper class for the attribution phase. 89 * 90 * <p><b>This is NOT part of any supported API. 91 * If you write code that depends on this, you do so at your own risk. 92 * This code and its internal interfaces are subject to change or 93 * deletion without notice.</b> 94 */ 95 public class Check { 96 protected static final Context.Key<Check> checkKey = new Context.Key<>(); 97 98 // Flag bits indicating which item(s) chosen from a pair of items 99 private static final int FIRST = 0x01; 100 private static final int SECOND = 0x02; 101 102 private final Names names; 103 private final Log log; 104 private final Resolve rs; 105 private final Symtab syms; 106 private final Enter enter; 107 private final DeferredAttr deferredAttr; 108 private final Infer infer; 109 private final Types types; 110 private final TypeAnnotations typeAnnotations; 111 private final JCDiagnostic.Factory diags; 112 private final JavaFileManager fileManager; 113 private final Source source; 114 private final Target target; 115 private final Profile profile; 116 private final Preview preview; 117 private final boolean warnOnAnyAccessToMembers; 118 119 public boolean disablePreviewCheck; 120 121 // The set of lint options currently in effect. It is initialized 122 // from the context, and then is set/reset as needed by Attr as it 123 // visits all the various parts of the trees during attribution. 124 private Lint lint; 125 126 // The method being analyzed in Attr - it is set/reset as needed by 127 // Attr as it visits new method declarations. 128 private MethodSymbol method; 129 130 public static Check instance(Context context) { 131 Check instance = context.get(checkKey); 132 if (instance == null) 133 instance = new Check(context); 134 return instance; 135 } 136 137 @SuppressWarnings("this-escape") 138 protected Check(Context context) { 139 context.put(checkKey, this); 140 141 names = Names.instance(context); 142 log = Log.instance(context); 143 rs = Resolve.instance(context); 144 syms = Symtab.instance(context); 145 enter = Enter.instance(context); 146 deferredAttr = DeferredAttr.instance(context); 147 infer = Infer.instance(context); 148 types = Types.instance(context); 149 typeAnnotations = TypeAnnotations.instance(context); 150 diags = JCDiagnostic.Factory.instance(context); 151 Options options = Options.instance(context); 152 lint = Lint.instance(context); 153 fileManager = context.get(JavaFileManager.class); 154 155 source = Source.instance(context); 156 target = Target.instance(context); 157 warnOnAnyAccessToMembers = options.isSet("warnOnAccessToMembers"); 158 159 disablePreviewCheck = false; 160 161 Target target = Target.instance(context); 162 syntheticNameChar = target.syntheticNameChar(); 163 164 profile = Profile.instance(context); 165 preview = Preview.instance(context); 166 167 allowModules = Feature.MODULES.allowedInSource(source); 168 allowRecords = Feature.RECORDS.allowedInSource(source); 169 allowSealed = Feature.SEALED_CLASSES.allowedInSource(source); 170 } 171 172 /** Character for synthetic names 173 */ 174 char syntheticNameChar; 175 176 /** A table mapping flat names of all compiled classes for each module in this run 177 * to their symbols; maintained from outside. 178 */ 179 private Map<Pair<ModuleSymbol, Name>,ClassSymbol> compiled = new HashMap<>(); 180 181 /** Are modules allowed 182 */ 183 private final boolean allowModules; 184 185 /** Are records allowed 186 */ 187 private final boolean allowRecords; 188 189 /** Are sealed classes allowed 190 */ 191 private final boolean allowSealed; 192 193 /** Whether to force suppression of deprecation and preview warnings. 194 * This happens when attributing import statements for JDK 9+. 195 * @see Feature#DEPRECATION_ON_IMPORT 196 */ 197 private boolean importSuppression; 198 199 /* ************************************************************************* 200 * Errors and Warnings 201 **************************************************************************/ 202 203 Lint setLint(Lint newLint) { 204 Lint prev = lint; 205 lint = newLint; 206 return prev; 207 } 208 209 boolean setImportSuppression(boolean newImportSuppression) { 210 boolean prev = importSuppression; 211 importSuppression = newImportSuppression; 212 return prev; 213 } 214 215 MethodSymbol setMethod(MethodSymbol newMethod) { 216 MethodSymbol prev = method; 217 method = newMethod; 218 return prev; 219 } 220 221 /** Warn about deprecated symbol. 222 * @param pos Position to be used for error reporting. 223 * @param sym The deprecated symbol. 224 */ 225 void warnDeprecated(DiagnosticPosition pos, Symbol sym) { 226 Assert.check(!importSuppression); 227 LintWarning warningKey = sym.isDeprecatedForRemoval() ? 228 (sym.kind == MDL ? 229 LintWarnings.HasBeenDeprecatedForRemovalModule(sym) : 230 LintWarnings.HasBeenDeprecatedForRemoval(sym, sym.location())) : 231 (sym.kind == MDL ? 232 LintWarnings.HasBeenDeprecatedModule(sym) : 233 LintWarnings.HasBeenDeprecated(sym, sym.location())); 234 log.warning(pos, warningKey); 235 } 236 237 /** Log a preview warning. 238 * @param pos Position to be used for error reporting. 239 * @param msg A Warning describing the problem. 240 */ 241 public void warnPreviewAPI(DiagnosticPosition pos, LintWarning warnKey) { 242 if (!importSuppression) 243 log.warning(pos, warnKey); 244 } 245 246 /** Warn about unchecked operation. 247 * @param pos Position to be used for error reporting. 248 * @param msg A string describing the problem. 249 */ 250 public void warnUnchecked(DiagnosticPosition pos, LintWarning warnKey) { 251 log.warning(pos, warnKey); 252 } 253 254 /** Report a failure to complete a class. 255 * @param pos Position to be used for error reporting. 256 * @param ex The failure to report. 257 */ 258 public Type completionError(DiagnosticPosition pos, CompletionFailure ex) { 259 log.error(DiagnosticFlag.NON_DEFERRABLE, pos, Errors.CantAccess(ex.sym, ex.getDetailValue())); 260 return syms.errType; 261 } 262 263 /** Report an error that wrong type tag was found. 264 * @param pos Position to be used for error reporting. 265 * @param required An internationalized string describing the type tag 266 * required. 267 * @param found The type that was found. 268 */ 269 Type typeTagError(DiagnosticPosition pos, JCDiagnostic required, Object found) { 270 // this error used to be raised by the parser, 271 // but has been delayed to this point: 272 if (found instanceof Type type && type.hasTag(VOID)) { 273 log.error(pos, Errors.IllegalStartOfType); 274 return syms.errType; 275 } 276 log.error(pos, Errors.TypeFoundReq(found, required)); 277 return types.createErrorType(found instanceof Type type ? type : syms.errType); 278 } 279 280 /** Report duplicate declaration error. 281 */ 282 void duplicateError(DiagnosticPosition pos, Symbol sym) { 283 if (!sym.type.isErroneous()) { 284 Symbol location = sym.location(); 285 if (location.kind == MTH && 286 ((MethodSymbol)location).isStaticOrInstanceInit()) { 287 log.error(pos, 288 Errors.AlreadyDefinedInClinit(kindName(sym), 289 sym, 290 kindName(sym.location()), 291 kindName(sym.location().enclClass()), 292 sym.location().enclClass())); 293 } else { 294 /* dont error if this is a duplicated parameter of a generated canonical constructor 295 * as we should have issued an error for the duplicated fields 296 */ 297 if (location.kind != MTH || 298 ((sym.owner.flags_field & GENERATEDCONSTR) == 0) || 299 ((sym.owner.flags_field & RECORD) == 0)) { 300 log.error(pos, 301 Errors.AlreadyDefined(kindName(sym), 302 sym, 303 kindName(sym.location()), 304 sym.location())); 305 } 306 } 307 } 308 } 309 310 /** Report array/varargs duplicate declaration 311 */ 312 void varargsDuplicateError(DiagnosticPosition pos, Symbol sym1, Symbol sym2) { 313 if (!sym1.type.isErroneous() && !sym2.type.isErroneous()) { 314 log.error(pos, Errors.ArrayAndVarargs(sym1, sym2, sym2.location())); 315 } 316 } 317 318 /* ************************************************************************ 319 * duplicate declaration checking 320 *************************************************************************/ 321 322 /** Check that variable does not hide variable with same name in 323 * immediately enclosing local scope. 324 * @param pos Position for error reporting. 325 * @param v The symbol. 326 * @param s The scope. 327 */ 328 void checkTransparentVar(DiagnosticPosition pos, VarSymbol v, Scope s) { 329 for (Symbol sym : s.getSymbolsByName(v.name)) { 330 if (sym.owner != v.owner) break; 331 if (sym.kind == VAR && 332 sym.owner.kind.matches(KindSelector.VAL_MTH) && 333 v.name != names.error) { 334 duplicateError(pos, sym); 335 return; 336 } 337 } 338 } 339 340 /** Check that a class or interface does not hide a class or 341 * interface with same name in immediately enclosing local scope. 342 * @param pos Position for error reporting. 343 * @param c The symbol. 344 * @param s The scope. 345 */ 346 void checkTransparentClass(DiagnosticPosition pos, ClassSymbol c, Scope s) { 347 for (Symbol sym : s.getSymbolsByName(c.name)) { 348 if (sym.owner != c.owner) break; 349 if (sym.kind == TYP && !sym.type.hasTag(TYPEVAR) && 350 sym.owner.kind.matches(KindSelector.VAL_MTH) && 351 c.name != names.error) { 352 duplicateError(pos, sym); 353 return; 354 } 355 } 356 } 357 358 /** Check that class does not have the same name as one of 359 * its enclosing classes, or as a class defined in its enclosing scope. 360 * return true if class is unique in its enclosing scope. 361 * @param pos Position for error reporting. 362 * @param name The class name. 363 * @param s The enclosing scope. 364 */ 365 boolean checkUniqueClassName(DiagnosticPosition pos, Name name, Scope s) { 366 for (Symbol sym : s.getSymbolsByName(name, NON_RECURSIVE)) { 367 if (sym.kind == TYP && sym.name != names.error) { 368 duplicateError(pos, sym); 369 return false; 370 } 371 } 372 for (Symbol sym = s.owner; sym != null; sym = sym.owner) { 373 if (sym.kind == TYP && sym.name == name && sym.name != names.error && 374 !sym.isImplicit()) { 375 duplicateError(pos, sym); 376 return true; 377 } 378 } 379 return true; 380 } 381 382 /* ************************************************************************* 383 * Class name generation 384 **************************************************************************/ 385 386 387 private Map<Pair<Name, Name>, Integer> localClassNameIndexes = new HashMap<>(); 388 389 /** Return name of local class. 390 * This is of the form {@code <enclClass> $ n <classname> } 391 * where 392 * enclClass is the flat name of the enclosing class, 393 * classname is the simple name of the local class 394 */ 395 public Name localClassName(ClassSymbol c) { 396 Name enclFlatname = c.owner.enclClass().flatname; 397 String enclFlatnameStr = enclFlatname.toString(); 398 Pair<Name, Name> key = new Pair<>(enclFlatname, c.name); 399 Integer index = localClassNameIndexes.get(key); 400 for (int i = (index == null) ? 1 : index; ; i++) { 401 Name flatname = names.fromString(enclFlatnameStr 402 + syntheticNameChar + i + c.name); 403 if (getCompiled(c.packge().modle, flatname) == null) { 404 localClassNameIndexes.put(key, i + 1); 405 return flatname; 406 } 407 } 408 } 409 410 public void clearLocalClassNameIndexes(ClassSymbol c) { 411 if (c.owner != null && c.owner.kind != NIL) { 412 localClassNameIndexes.remove(new Pair<>( 413 c.owner.enclClass().flatname, c.name)); 414 } 415 } 416 417 public void newRound() { 418 compiled.clear(); 419 localClassNameIndexes.clear(); 420 } 421 422 public void putCompiled(ClassSymbol csym) { 423 compiled.put(Pair.of(csym.packge().modle, csym.flatname), csym); 424 } 425 426 public ClassSymbol getCompiled(ClassSymbol csym) { 427 return compiled.get(Pair.of(csym.packge().modle, csym.flatname)); 428 } 429 430 public ClassSymbol getCompiled(ModuleSymbol msym, Name flatname) { 431 return compiled.get(Pair.of(msym, flatname)); 432 } 433 434 public void removeCompiled(ClassSymbol csym) { 435 compiled.remove(Pair.of(csym.packge().modle, csym.flatname)); 436 } 437 438 /* ************************************************************************* 439 * Type Checking 440 **************************************************************************/ 441 442 /** 443 * A check context is an object that can be used to perform compatibility 444 * checks - depending on the check context, meaning of 'compatibility' might 445 * vary significantly. 446 */ 447 public interface CheckContext { 448 /** 449 * Is type 'found' compatible with type 'req' in given context 450 */ 451 boolean compatible(Type found, Type req, Warner warn); 452 /** 453 * Report a check error 454 */ 455 void report(DiagnosticPosition pos, JCDiagnostic details); 456 /** 457 * Obtain a warner for this check context 458 */ 459 public Warner checkWarner(DiagnosticPosition pos, Type found, Type req); 460 461 public InferenceContext inferenceContext(); 462 463 public DeferredAttr.DeferredAttrContext deferredAttrContext(); 464 } 465 466 /** 467 * This class represent a check context that is nested within another check 468 * context - useful to check sub-expressions. The default behavior simply 469 * redirects all method calls to the enclosing check context leveraging 470 * the forwarding pattern. 471 */ 472 static class NestedCheckContext implements CheckContext { 473 CheckContext enclosingContext; 474 475 NestedCheckContext(CheckContext enclosingContext) { 476 this.enclosingContext = enclosingContext; 477 } 478 479 public boolean compatible(Type found, Type req, Warner warn) { 480 return enclosingContext.compatible(found, req, warn); 481 } 482 483 public void report(DiagnosticPosition pos, JCDiagnostic details) { 484 enclosingContext.report(pos, details); 485 } 486 487 public Warner checkWarner(DiagnosticPosition pos, Type found, Type req) { 488 return enclosingContext.checkWarner(pos, found, req); 489 } 490 491 public InferenceContext inferenceContext() { 492 return enclosingContext.inferenceContext(); 493 } 494 495 public DeferredAttrContext deferredAttrContext() { 496 return enclosingContext.deferredAttrContext(); 497 } 498 } 499 500 /** 501 * Check context to be used when evaluating assignment/return statements 502 */ 503 CheckContext basicHandler = new CheckContext() { 504 public void report(DiagnosticPosition pos, JCDiagnostic details) { 505 log.error(pos, Errors.ProbFoundReq(details)); 506 } 507 public boolean compatible(Type found, Type req, Warner warn) { 508 return types.isAssignable(found, req, warn); 509 } 510 511 public Warner checkWarner(DiagnosticPosition pos, Type found, Type req) { 512 return convertWarner(pos, found, req); 513 } 514 515 public InferenceContext inferenceContext() { 516 return infer.emptyContext; 517 } 518 519 public DeferredAttrContext deferredAttrContext() { 520 return deferredAttr.emptyDeferredAttrContext; 521 } 522 523 @Override 524 public String toString() { 525 return "CheckContext: basicHandler"; 526 } 527 }; 528 529 /** Check that a given type is assignable to a given proto-type. 530 * If it is, return the type, otherwise return errType. 531 * @param pos Position to be used for error reporting. 532 * @param found The type that was found. 533 * @param req The type that was required. 534 */ 535 public Type checkType(DiagnosticPosition pos, Type found, Type req) { 536 return checkType(pos, found, req, basicHandler); 537 } 538 539 Type checkType(final DiagnosticPosition pos, final Type found, final Type req, final CheckContext checkContext) { 540 final InferenceContext inferenceContext = checkContext.inferenceContext(); 541 if (inferenceContext.free(req) || inferenceContext.free(found)) { 542 inferenceContext.addFreeTypeListener(List.of(req, found), 543 solvedContext -> checkType(pos, solvedContext.asInstType(found), solvedContext.asInstType(req), checkContext)); 544 } 545 if (req.hasTag(ERROR)) 546 return req; 547 if (req.hasTag(NONE)) 548 return found; 549 if (checkContext.compatible(found, req, checkContext.checkWarner(pos, found, req))) { 550 return found; 551 } else { 552 if (found.isNumeric() && req.isNumeric()) { 553 checkContext.report(pos, diags.fragment(Fragments.PossibleLossOfPrecision(found, req))); 554 return types.createErrorType(found); 555 } 556 checkContext.report(pos, diags.fragment(Fragments.InconvertibleTypes(found, req))); 557 return types.createErrorType(found); 558 } 559 } 560 561 /** Check that a given type can be cast to a given target type. 562 * Return the result of the cast. 563 * @param pos Position to be used for error reporting. 564 * @param found The type that is being cast. 565 * @param req The target type of the cast. 566 */ 567 Type checkCastable(DiagnosticPosition pos, Type found, Type req) { 568 return checkCastable(pos, found, req, basicHandler); 569 } 570 Type checkCastable(DiagnosticPosition pos, Type found, Type req, CheckContext checkContext) { 571 if (types.isCastable(found, req, castWarner(pos, found, req))) { 572 return req; 573 } else { 574 checkContext.report(pos, diags.fragment(Fragments.InconvertibleTypes(found, req))); 575 return types.createErrorType(found); 576 } 577 } 578 579 /** Check for redundant casts (i.e. where source type is a subtype of target type) 580 * The problem should only be reported for non-292 cast 581 */ 582 public void checkRedundantCast(Env<AttrContext> env, final JCTypeCast tree) { 583 if (!tree.type.isErroneous() 584 && types.isSameType(tree.expr.type, tree.clazz.type) 585 && !(ignoreAnnotatedCasts && TreeInfo.containsTypeAnnotation(tree.clazz)) 586 && !is292targetTypeCast(tree)) { 587 log.warning(tree.pos(), LintWarnings.RedundantCast(tree.clazz.type)); 588 } 589 } 590 //where 591 private boolean is292targetTypeCast(JCTypeCast tree) { 592 boolean is292targetTypeCast = false; 593 JCExpression expr = TreeInfo.skipParens(tree.expr); 594 if (expr.hasTag(APPLY)) { 595 JCMethodInvocation apply = (JCMethodInvocation)expr; 596 Symbol sym = TreeInfo.symbol(apply.meth); 597 is292targetTypeCast = sym != null && 598 sym.kind == MTH && 599 (sym.flags() & HYPOTHETICAL) != 0; 600 } 601 return is292targetTypeCast; 602 } 603 604 private static final boolean ignoreAnnotatedCasts = true; 605 606 /** Check that a type is within some bounds. 607 * 608 * Used in TypeApply to verify that, e.g., X in {@code V<X>} is a valid 609 * type argument. 610 * @param a The type that should be bounded by bs. 611 * @param bound The bound. 612 */ 613 private boolean checkExtends(Type a, Type bound) { 614 if (a.isUnbound()) { 615 return true; 616 } else if (!a.hasTag(WILDCARD)) { 617 a = types.cvarUpperBound(a); 618 return types.isSubtype(a, bound); 619 } else if (a.isExtendsBound()) { 620 return types.isCastable(bound, types.wildUpperBound(a), types.noWarnings); 621 } else if (a.isSuperBound()) { 622 return !types.notSoftSubtype(types.wildLowerBound(a), bound); 623 } 624 return true; 625 } 626 627 /** Check that type is different from 'void'. 628 * @param pos Position to be used for error reporting. 629 * @param t The type to be checked. 630 */ 631 Type checkNonVoid(DiagnosticPosition pos, Type t) { 632 if (t.hasTag(VOID)) { 633 log.error(pos, Errors.VoidNotAllowedHere); 634 return types.createErrorType(t); 635 } else { 636 return t; 637 } 638 } 639 640 Type checkClassOrArrayType(DiagnosticPosition pos, Type t) { 641 if (!t.hasTag(CLASS) && !t.hasTag(ARRAY) && !t.hasTag(ERROR)) { 642 return typeTagError(pos, 643 diags.fragment(Fragments.TypeReqClassArray), 644 asTypeParam(t)); 645 } else { 646 return t; 647 } 648 } 649 650 /** Check that type is a class or interface type. 651 * @param pos Position to be used for error reporting. 652 * @param t The type to be checked. 653 */ 654 Type checkClassType(DiagnosticPosition pos, Type t) { 655 if (!t.hasTag(CLASS) && !t.hasTag(ERROR)) { 656 return typeTagError(pos, 657 diags.fragment(Fragments.TypeReqClass), 658 asTypeParam(t)); 659 } else { 660 return t; 661 } 662 } 663 //where 664 private Object asTypeParam(Type t) { 665 return (t.hasTag(TYPEVAR)) 666 ? diags.fragment(Fragments.TypeParameter(t)) 667 : t; 668 } 669 670 /** Check that type is a valid qualifier for a constructor reference expression 671 */ 672 Type checkConstructorRefType(DiagnosticPosition pos, Type t) { 673 t = checkClassOrArrayType(pos, t); 674 if (t.hasTag(CLASS)) { 675 if ((t.tsym.flags() & (ABSTRACT | INTERFACE)) != 0) { 676 log.error(pos, Errors.AbstractCantBeInstantiated(t.tsym)); 677 t = types.createErrorType(t); 678 } else if ((t.tsym.flags() & ENUM) != 0) { 679 log.error(pos, Errors.EnumCantBeInstantiated); 680 t = types.createErrorType(t); 681 } else { 682 t = checkClassType(pos, t, true); 683 } 684 } else if (t.hasTag(ARRAY)) { 685 if (!types.isReifiable(((ArrayType)t).elemtype)) { 686 log.error(pos, Errors.GenericArrayCreation); 687 t = types.createErrorType(t); 688 } 689 } 690 return t; 691 } 692 693 /** Check that type is a class or interface type. 694 * @param pos Position to be used for error reporting. 695 * @param t The type to be checked. 696 * @param noBounds True if type bounds are illegal here. 697 */ 698 Type checkClassType(DiagnosticPosition pos, Type t, boolean noBounds) { 699 t = checkClassType(pos, t); 700 if (noBounds && t.isParameterized()) { 701 List<Type> args = t.getTypeArguments(); 702 while (args.nonEmpty()) { 703 if (args.head.hasTag(WILDCARD)) 704 return typeTagError(pos, 705 diags.fragment(Fragments.TypeReqExact), 706 args.head); 707 args = args.tail; 708 } 709 } 710 return t; 711 } 712 713 /** Check that type is a reference type, i.e. a class, interface or array type 714 * or a type variable. 715 * @param pos Position to be used for error reporting. 716 * @param t The type to be checked. 717 */ 718 Type checkRefType(DiagnosticPosition pos, Type t) { 719 if (t.isReference()) 720 return t; 721 else 722 return typeTagError(pos, 723 diags.fragment(Fragments.TypeReqRef), 724 t); 725 } 726 727 /** Check that each type is a reference type, i.e. a class, interface or array type 728 * or a type variable. 729 * @param trees Original trees, used for error reporting. 730 * @param types The types to be checked. 731 */ 732 List<Type> checkRefTypes(List<JCExpression> trees, List<Type> types) { 733 List<JCExpression> tl = trees; 734 for (List<Type> l = types; l.nonEmpty(); l = l.tail) { 735 l.head = checkRefType(tl.head.pos(), l.head); 736 tl = tl.tail; 737 } 738 return types; 739 } 740 741 /** Check that type is a null or reference type. 742 * @param pos Position to be used for error reporting. 743 * @param t The type to be checked. 744 */ 745 Type checkNullOrRefType(DiagnosticPosition pos, Type t) { 746 if (t.isReference() || t.hasTag(BOT)) 747 return t; 748 else 749 return typeTagError(pos, 750 diags.fragment(Fragments.TypeReqRef), 751 t); 752 } 753 754 /** Check that flag set does not contain elements of two conflicting sets. s 755 * Return true if it doesn't. 756 * @param pos Position to be used for error reporting. 757 * @param flags The set of flags to be checked. 758 * @param set1 Conflicting flags set #1. 759 * @param set2 Conflicting flags set #2. 760 */ 761 boolean checkDisjoint(DiagnosticPosition pos, long flags, long set1, long set2) { 762 if ((flags & set1) != 0 && (flags & set2) != 0) { 763 log.error(pos, 764 Errors.IllegalCombinationOfModifiers(asFlagSet(TreeInfo.firstFlag(flags & set1)), 765 asFlagSet(TreeInfo.firstFlag(flags & set2)))); 766 return false; 767 } else 768 return true; 769 } 770 771 /** Check that usage of diamond operator is correct (i.e. diamond should not 772 * be used with non-generic classes or in anonymous class creation expressions) 773 */ 774 Type checkDiamond(JCNewClass tree, Type t) { 775 if (!TreeInfo.isDiamond(tree) || 776 t.isErroneous()) { 777 return checkClassType(tree.clazz.pos(), t, true); 778 } else { 779 if (tree.def != null && !Feature.DIAMOND_WITH_ANONYMOUS_CLASS_CREATION.allowedInSource(source)) { 780 log.error(DiagnosticFlag.SOURCE_LEVEL, tree.clazz.pos(), 781 Errors.CantApplyDiamond1(t, Feature.DIAMOND_WITH_ANONYMOUS_CLASS_CREATION.fragment(source.name))); 782 } 783 if (t.tsym.type.getTypeArguments().isEmpty()) { 784 log.error(tree.clazz.pos(), 785 Errors.CantApplyDiamond1(t, 786 Fragments.DiamondNonGeneric(t))); 787 return types.createErrorType(t); 788 } else if (tree.typeargs != null && 789 tree.typeargs.nonEmpty()) { 790 log.error(tree.clazz.pos(), 791 Errors.CantApplyDiamond1(t, 792 Fragments.DiamondAndExplicitParams(t))); 793 return types.createErrorType(t); 794 } else { 795 return t; 796 } 797 } 798 } 799 800 /** Check that the type inferred using the diamond operator does not contain 801 * non-denotable types such as captured types or intersection types. 802 * @param t the type inferred using the diamond operator 803 * @return the (possibly empty) list of non-denotable types. 804 */ 805 List<Type> checkDiamondDenotable(ClassType t) { 806 ListBuffer<Type> buf = new ListBuffer<>(); 807 for (Type arg : t.allparams()) { 808 if (!checkDenotable(arg)) { 809 buf.append(arg); 810 } 811 } 812 return buf.toList(); 813 } 814 815 public boolean checkDenotable(Type t) { 816 return denotableChecker.visit(t, null); 817 } 818 // where 819 820 /** diamondTypeChecker: A type visitor that descends down the given type looking for non-denotable 821 * types. The visit methods return false as soon as a non-denotable type is encountered and true 822 * otherwise. 823 */ 824 private static final Types.SimpleVisitor<Boolean, Void> denotableChecker = new Types.SimpleVisitor<Boolean, Void>() { 825 @Override 826 public Boolean visitType(Type t, Void s) { 827 return true; 828 } 829 @Override 830 public Boolean visitClassType(ClassType t, Void s) { 831 if (t.isUnion() || t.isIntersection()) { 832 return false; 833 } 834 for (Type targ : t.allparams()) { 835 if (!visit(targ, s)) { 836 return false; 837 } 838 } 839 return true; 840 } 841 842 @Override 843 public Boolean visitTypeVar(TypeVar t, Void s) { 844 /* Any type variable mentioned in the inferred type must have been declared as a type parameter 845 (i.e cannot have been produced by inference (18.4)) 846 */ 847 return (t.tsym.flags() & SYNTHETIC) == 0; 848 } 849 850 @Override 851 public Boolean visitCapturedType(CapturedType t, Void s) { 852 /* Any type variable mentioned in the inferred type must have been declared as a type parameter 853 (i.e cannot have been produced by capture conversion (5.1.10)) 854 */ 855 return false; 856 } 857 858 @Override 859 public Boolean visitArrayType(ArrayType t, Void s) { 860 return visit(t.elemtype, s); 861 } 862 863 @Override 864 public Boolean visitWildcardType(WildcardType t, Void s) { 865 return visit(t.type, s); 866 } 867 }; 868 869 void checkVarargsMethodDecl(Env<AttrContext> env, JCMethodDecl tree) { 870 MethodSymbol m = tree.sym; 871 boolean hasTrustMeAnno = m.attribute(syms.trustMeType.tsym) != null; 872 Type varargElemType = null; 873 if (m.isVarArgs()) { 874 varargElemType = types.elemtype(tree.params.last().type); 875 } 876 if (hasTrustMeAnno && !isTrustMeAllowedOnMethod(m)) { 877 if (varargElemType != null) { 878 JCDiagnostic msg = Feature.PRIVATE_SAFE_VARARGS.allowedInSource(source) ? 879 diags.fragment(Fragments.VarargsTrustmeOnVirtualVarargs(m)) : 880 diags.fragment(Fragments.VarargsTrustmeOnVirtualVarargsFinalOnly(m)); 881 log.error(tree, 882 Errors.VarargsInvalidTrustmeAnno(syms.trustMeType.tsym, 883 msg)); 884 } else { 885 log.error(tree, 886 Errors.VarargsInvalidTrustmeAnno(syms.trustMeType.tsym, 887 Fragments.VarargsTrustmeOnNonVarargsMeth(m))); 888 } 889 } else if (hasTrustMeAnno && varargElemType != null && 890 types.isReifiable(varargElemType)) { 891 log.warning(tree.pos(), LintWarnings.VarargsRedundantTrustmeAnno( 892 syms.trustMeType.tsym, 893 diags.fragment(Fragments.VarargsTrustmeOnReifiableVarargs(varargElemType)))); 894 } 895 else if (!hasTrustMeAnno && varargElemType != null && 896 !types.isReifiable(varargElemType)) { 897 warnUnchecked(tree.params.head.pos(), LintWarnings.UncheckedVarargsNonReifiableType(varargElemType)); 898 } 899 } 900 //where 901 private boolean isTrustMeAllowedOnMethod(Symbol s) { 902 return (s.flags() & VARARGS) != 0 && 903 (s.isConstructor() || 904 (s.flags() & (STATIC | FINAL | 905 (Feature.PRIVATE_SAFE_VARARGS.allowedInSource(source) ? PRIVATE : 0) )) != 0); 906 } 907 908 Type checkLocalVarType(DiagnosticPosition pos, Type t, Name name) { 909 //check that resulting type is not the null type 910 if (t.hasTag(BOT)) { 911 log.error(pos, Errors.CantInferLocalVarType(name, Fragments.LocalCantInferNull)); 912 return types.createErrorType(t); 913 } else if (t.hasTag(VOID)) { 914 log.error(pos, Errors.CantInferLocalVarType(name, Fragments.LocalCantInferVoid)); 915 return types.createErrorType(t); 916 } 917 918 //upward project the initializer type 919 return types.upward(t, types.captures(t)).baseType(); 920 } 921 922 Type checkMethod(final Type mtype, 923 final Symbol sym, 924 final Env<AttrContext> env, 925 final List<JCExpression> argtrees, 926 final List<Type> argtypes, 927 final boolean useVarargs, 928 InferenceContext inferenceContext) { 929 // System.out.println("call : " + env.tree); 930 // System.out.println("method : " + owntype); 931 // System.out.println("actuals: " + argtypes); 932 if (inferenceContext.free(mtype)) { 933 inferenceContext.addFreeTypeListener(List.of(mtype), 934 solvedContext -> checkMethod(solvedContext.asInstType(mtype), sym, env, argtrees, argtypes, useVarargs, solvedContext)); 935 return mtype; 936 } 937 Type owntype = mtype; 938 List<Type> formals = owntype.getParameterTypes(); 939 List<Type> nonInferred = sym.type.getParameterTypes(); 940 if (nonInferred.length() != formals.length()) nonInferred = formals; 941 Type last = useVarargs ? formals.last() : null; 942 if (sym.name == names.init && sym.owner == syms.enumSym) { 943 formals = formals.tail.tail; 944 nonInferred = nonInferred.tail.tail; 945 } 946 if ((sym.flags() & ANONCONSTR_BASED) != 0) { 947 formals = formals.tail; 948 nonInferred = nonInferred.tail; 949 } 950 List<JCExpression> args = argtrees; 951 if (args != null) { 952 //this is null when type-checking a method reference 953 while (formals.head != last) { 954 JCTree arg = args.head; 955 Warner warn = convertWarner(arg.pos(), arg.type, nonInferred.head); 956 assertConvertible(arg, arg.type, formals.head, warn); 957 args = args.tail; 958 formals = formals.tail; 959 nonInferred = nonInferred.tail; 960 } 961 if (useVarargs) { 962 Type varArg = types.elemtype(last); 963 while (args.tail != null) { 964 JCTree arg = args.head; 965 Warner warn = convertWarner(arg.pos(), arg.type, varArg); 966 assertConvertible(arg, arg.type, varArg, warn); 967 args = args.tail; 968 } 969 } else if ((sym.flags() & (VARARGS | SIGNATURE_POLYMORPHIC)) == VARARGS) { 970 // non-varargs call to varargs method 971 Type varParam = owntype.getParameterTypes().last(); 972 Type lastArg = argtypes.last(); 973 if (types.isSubtypeUnchecked(lastArg, types.elemtype(varParam)) && 974 !types.isSameType(types.erasure(varParam), types.erasure(lastArg))) 975 log.warning(argtrees.last().pos(), 976 Warnings.InexactNonVarargsCall(types.elemtype(varParam),varParam)); 977 } 978 } 979 if (useVarargs) { 980 Type argtype = owntype.getParameterTypes().last(); 981 if (!types.isReifiable(argtype) && 982 (sym.baseSymbol().attribute(syms.trustMeType.tsym) == null || 983 !isTrustMeAllowedOnMethod(sym))) { 984 warnUnchecked(env.tree.pos(), LintWarnings.UncheckedGenericArrayCreation(argtype)); 985 } 986 TreeInfo.setVarargsElement(env.tree, types.elemtype(argtype)); 987 } 988 return owntype; 989 } 990 //where 991 private void assertConvertible(JCTree tree, Type actual, Type formal, Warner warn) { 992 if (types.isConvertible(actual, formal, warn)) 993 return; 994 995 if (formal.isCompound() 996 && types.isSubtype(actual, types.supertype(formal)) 997 && types.isSubtypeUnchecked(actual, types.interfaces(formal), warn)) 998 return; 999 } 1000 1001 /** 1002 * Check that type 't' is a valid instantiation of a generic class 1003 * (see JLS 4.5) 1004 * 1005 * @param t class type to be checked 1006 * @return true if 't' is well-formed 1007 */ 1008 public boolean checkValidGenericType(Type t) { 1009 return firstIncompatibleTypeArg(t) == null; 1010 } 1011 //WHERE 1012 private Type firstIncompatibleTypeArg(Type type) { 1013 List<Type> formals = type.tsym.type.allparams(); 1014 List<Type> actuals = type.allparams(); 1015 List<Type> args = type.getTypeArguments(); 1016 List<Type> forms = type.tsym.type.getTypeArguments(); 1017 ListBuffer<Type> bounds_buf = new ListBuffer<>(); 1018 1019 // For matching pairs of actual argument types `a' and 1020 // formal type parameters with declared bound `b' ... 1021 while (args.nonEmpty() && forms.nonEmpty()) { 1022 // exact type arguments needs to know their 1023 // bounds (for upper and lower bound 1024 // calculations). So we create new bounds where 1025 // type-parameters are replaced with actuals argument types. 1026 bounds_buf.append(types.subst(forms.head.getUpperBound(), formals, actuals)); 1027 args = args.tail; 1028 forms = forms.tail; 1029 } 1030 1031 args = type.getTypeArguments(); 1032 List<Type> tvars_cap = types.substBounds(formals, 1033 formals, 1034 types.capture(type).allparams()); 1035 while (args.nonEmpty() && tvars_cap.nonEmpty()) { 1036 // Let the actual arguments know their bound 1037 args.head.withTypeVar((TypeVar)tvars_cap.head); 1038 args = args.tail; 1039 tvars_cap = tvars_cap.tail; 1040 } 1041 1042 args = type.getTypeArguments(); 1043 List<Type> bounds = bounds_buf.toList(); 1044 1045 while (args.nonEmpty() && bounds.nonEmpty()) { 1046 Type actual = args.head; 1047 if (!isTypeArgErroneous(actual) && 1048 !bounds.head.isErroneous() && 1049 !checkExtends(actual, bounds.head)) { 1050 return args.head; 1051 } 1052 args = args.tail; 1053 bounds = bounds.tail; 1054 } 1055 1056 args = type.getTypeArguments(); 1057 bounds = bounds_buf.toList(); 1058 1059 for (Type arg : types.capture(type).getTypeArguments()) { 1060 if (arg.hasTag(TYPEVAR) && 1061 arg.getUpperBound().isErroneous() && 1062 !bounds.head.isErroneous() && 1063 !isTypeArgErroneous(args.head)) { 1064 return args.head; 1065 } 1066 bounds = bounds.tail; 1067 args = args.tail; 1068 } 1069 1070 return null; 1071 } 1072 //where 1073 boolean isTypeArgErroneous(Type t) { 1074 return isTypeArgErroneous.visit(t); 1075 } 1076 1077 Types.UnaryVisitor<Boolean> isTypeArgErroneous = new Types.UnaryVisitor<Boolean>() { 1078 public Boolean visitType(Type t, Void s) { 1079 return t.isErroneous(); 1080 } 1081 @Override 1082 public Boolean visitTypeVar(TypeVar t, Void s) { 1083 return visit(t.getUpperBound()); 1084 } 1085 @Override 1086 public Boolean visitCapturedType(CapturedType t, Void s) { 1087 return visit(t.getUpperBound()) || 1088 visit(t.getLowerBound()); 1089 } 1090 @Override 1091 public Boolean visitWildcardType(WildcardType t, Void s) { 1092 return visit(t.type); 1093 } 1094 }; 1095 1096 /** Check that given modifiers are legal for given symbol and 1097 * return modifiers together with any implicit modifiers for that symbol. 1098 * Warning: we can't use flags() here since this method 1099 * is called during class enter, when flags() would cause a premature 1100 * completion. 1101 * @param flags The set of modifiers given in a definition. 1102 * @param sym The defined symbol. 1103 * @param tree The declaration 1104 */ 1105 long checkFlags(long flags, Symbol sym, JCTree tree) { 1106 final DiagnosticPosition pos = tree.pos(); 1107 long mask; 1108 long implicit = 0; 1109 1110 switch (sym.kind) { 1111 case VAR: 1112 if (TreeInfo.isReceiverParam(tree)) 1113 mask = ReceiverParamFlags; 1114 else if (sym.owner.kind != TYP) 1115 mask = LocalVarFlags; 1116 else if ((sym.owner.flags_field & INTERFACE) != 0) 1117 mask = implicit = InterfaceVarFlags; 1118 else 1119 mask = VarFlags; 1120 break; 1121 case MTH: 1122 if (sym.name == names.init) { 1123 if ((sym.owner.flags_field & ENUM) != 0) { 1124 // enum constructors cannot be declared public or 1125 // protected and must be implicitly or explicitly 1126 // private 1127 implicit = PRIVATE; 1128 mask = PRIVATE; 1129 } else 1130 mask = ConstructorFlags; 1131 } else if ((sym.owner.flags_field & INTERFACE) != 0) { 1132 if ((sym.owner.flags_field & ANNOTATION) != 0) { 1133 mask = AnnotationTypeElementMask; 1134 implicit = PUBLIC | ABSTRACT; 1135 } else if ((flags & (DEFAULT | STATIC | PRIVATE)) != 0) { 1136 mask = InterfaceMethodMask; 1137 implicit = (flags & PRIVATE) != 0 ? 0 : PUBLIC; 1138 if ((flags & DEFAULT) != 0) { 1139 implicit |= ABSTRACT; 1140 } 1141 } else { 1142 mask = implicit = InterfaceMethodFlags; 1143 } 1144 } else if ((sym.owner.flags_field & RECORD) != 0) { 1145 mask = RecordMethodFlags; 1146 } else { 1147 mask = MethodFlags; 1148 } 1149 if ((flags & STRICTFP) != 0) { 1150 log.warning(tree.pos(), LintWarnings.Strictfp); 1151 } 1152 // Imply STRICTFP if owner has STRICTFP set. 1153 if (((flags|implicit) & Flags.ABSTRACT) == 0 || 1154 ((flags) & Flags.DEFAULT) != 0) 1155 implicit |= sym.owner.flags_field & STRICTFP; 1156 break; 1157 case TYP: 1158 if (sym.owner.kind.matches(KindSelector.VAL_MTH) || 1159 (sym.isDirectlyOrIndirectlyLocal() && (flags & ANNOTATION) != 0)) { 1160 boolean implicitlyStatic = !sym.isAnonymous() && 1161 ((flags & RECORD) != 0 || (flags & ENUM) != 0 || (flags & INTERFACE) != 0); 1162 boolean staticOrImplicitlyStatic = (flags & STATIC) != 0 || implicitlyStatic; 1163 // local statics are allowed only if records are allowed too 1164 mask = staticOrImplicitlyStatic && allowRecords && (flags & ANNOTATION) == 0 ? StaticLocalFlags : LocalClassFlags; 1165 implicit = implicitlyStatic ? STATIC : implicit; 1166 } else if (sym.owner.kind == TYP) { 1167 // statics in inner classes are allowed only if records are allowed too 1168 mask = ((flags & STATIC) != 0) && allowRecords && (flags & ANNOTATION) == 0 ? ExtendedMemberStaticClassFlags : ExtendedMemberClassFlags; 1169 if (sym.owner.owner.kind == PCK || 1170 (sym.owner.flags_field & STATIC) != 0) { 1171 mask |= STATIC; 1172 } else if (!allowRecords && ((flags & ENUM) != 0 || (flags & RECORD) != 0)) { 1173 log.error(pos, Errors.StaticDeclarationNotAllowedInInnerClasses); 1174 } 1175 // Nested interfaces and enums are always STATIC (Spec ???) 1176 if ((flags & (INTERFACE | ENUM | RECORD)) != 0 ) implicit = STATIC; 1177 } else { 1178 mask = ExtendedClassFlags; 1179 } 1180 // Interfaces are always ABSTRACT 1181 if ((flags & INTERFACE) != 0) implicit |= ABSTRACT; 1182 1183 if ((flags & ENUM) != 0) { 1184 // enums can't be declared abstract, final, sealed or non-sealed 1185 mask &= ~(ABSTRACT | FINAL | SEALED | NON_SEALED); 1186 implicit |= implicitEnumFinalFlag(tree); 1187 } 1188 if ((flags & RECORD) != 0) { 1189 // records can't be declared abstract 1190 mask &= ~ABSTRACT; 1191 implicit |= FINAL; 1192 } 1193 if ((flags & STRICTFP) != 0) { 1194 log.warning(tree.pos(), LintWarnings.Strictfp); 1195 } 1196 // Imply STRICTFP if owner has STRICTFP set. 1197 implicit |= sym.owner.flags_field & STRICTFP; 1198 break; 1199 default: 1200 throw new AssertionError(); 1201 } 1202 long illegal = flags & ExtendedStandardFlags & ~mask; 1203 if (illegal != 0) { 1204 if ((illegal & INTERFACE) != 0) { 1205 log.error(pos, ((flags & ANNOTATION) != 0) ? Errors.AnnotationDeclNotAllowedHere : Errors.IntfNotAllowedHere); 1206 mask |= INTERFACE; 1207 } 1208 else { 1209 log.error(pos, 1210 Errors.ModNotAllowedHere(asFlagSet(illegal))); 1211 } 1212 } 1213 else if ((sym.kind == TYP || 1214 // ISSUE: Disallowing abstract&private is no longer appropriate 1215 // in the presence of inner classes. Should it be deleted here? 1216 checkDisjoint(pos, flags, 1217 ABSTRACT, 1218 PRIVATE | STATIC | DEFAULT)) 1219 && 1220 checkDisjoint(pos, flags, 1221 STATIC | PRIVATE, 1222 DEFAULT) 1223 && 1224 checkDisjoint(pos, flags, 1225 ABSTRACT | INTERFACE, 1226 FINAL | NATIVE | SYNCHRONIZED) 1227 && 1228 checkDisjoint(pos, flags, 1229 PUBLIC, 1230 PRIVATE | PROTECTED) 1231 && 1232 checkDisjoint(pos, flags, 1233 PRIVATE, 1234 PUBLIC | PROTECTED) 1235 && 1236 checkDisjoint(pos, flags, 1237 FINAL, 1238 VOLATILE) 1239 && 1240 (sym.kind == TYP || 1241 checkDisjoint(pos, flags, 1242 ABSTRACT | NATIVE, 1243 STRICTFP)) 1244 && checkDisjoint(pos, flags, 1245 FINAL, 1246 SEALED | NON_SEALED) 1247 && checkDisjoint(pos, flags, 1248 SEALED, 1249 FINAL | NON_SEALED) 1250 && checkDisjoint(pos, flags, 1251 SEALED, 1252 ANNOTATION)) { 1253 // skip 1254 } 1255 return flags & (mask | ~ExtendedStandardFlags) | implicit; 1256 } 1257 1258 /** Determine if this enum should be implicitly final. 1259 * 1260 * If the enum has no specialized enum constants, it is final. 1261 * 1262 * If the enum does have specialized enum constants, it is 1263 * <i>not</i> final. 1264 */ 1265 private long implicitEnumFinalFlag(JCTree tree) { 1266 if (!tree.hasTag(CLASSDEF)) return 0; 1267 class SpecialTreeVisitor extends JCTree.Visitor { 1268 boolean specialized; 1269 SpecialTreeVisitor() { 1270 this.specialized = false; 1271 } 1272 1273 @Override 1274 public void visitTree(JCTree tree) { /* no-op */ } 1275 1276 @Override 1277 public void visitVarDef(JCVariableDecl tree) { 1278 if ((tree.mods.flags & ENUM) != 0) { 1279 if (tree.init instanceof JCNewClass newClass && newClass.def != null) { 1280 specialized = true; 1281 } 1282 } 1283 } 1284 } 1285 1286 SpecialTreeVisitor sts = new SpecialTreeVisitor(); 1287 JCClassDecl cdef = (JCClassDecl) tree; 1288 for (JCTree defs: cdef.defs) { 1289 defs.accept(sts); 1290 if (sts.specialized) return allowSealed ? SEALED : 0; 1291 } 1292 return FINAL; 1293 } 1294 1295 /* ************************************************************************* 1296 * Type Validation 1297 **************************************************************************/ 1298 1299 /** Validate a type expression. That is, 1300 * check that all type arguments of a parametric type are within 1301 * their bounds. This must be done in a second phase after type attribution 1302 * since a class might have a subclass as type parameter bound. E.g: 1303 * 1304 * <pre>{@code 1305 * class B<A extends C> { ... } 1306 * class C extends B<C> { ... } 1307 * }</pre> 1308 * 1309 * and we can't make sure that the bound is already attributed because 1310 * of possible cycles. 1311 * 1312 * Visitor method: Validate a type expression, if it is not null, catching 1313 * and reporting any completion failures. 1314 */ 1315 void validate(JCTree tree, Env<AttrContext> env) { 1316 validate(tree, env, true); 1317 } 1318 void validate(JCTree tree, Env<AttrContext> env, boolean checkRaw) { 1319 new Validator(env).validateTree(tree, checkRaw, true); 1320 } 1321 1322 /** Visitor method: Validate a list of type expressions. 1323 */ 1324 void validate(List<? extends JCTree> trees, Env<AttrContext> env) { 1325 for (List<? extends JCTree> l = trees; l.nonEmpty(); l = l.tail) 1326 validate(l.head, env); 1327 } 1328 1329 /** A visitor class for type validation. 1330 */ 1331 class Validator extends JCTree.Visitor { 1332 1333 boolean checkRaw; 1334 boolean isOuter; 1335 Env<AttrContext> env; 1336 1337 Validator(Env<AttrContext> env) { 1338 this.env = env; 1339 } 1340 1341 @Override 1342 public void visitTypeArray(JCArrayTypeTree tree) { 1343 validateTree(tree.elemtype, checkRaw, isOuter); 1344 } 1345 1346 @Override 1347 public void visitTypeApply(JCTypeApply tree) { 1348 if (tree.type.hasTag(CLASS)) { 1349 List<JCExpression> args = tree.arguments; 1350 List<Type> forms = tree.type.tsym.type.getTypeArguments(); 1351 1352 Type incompatibleArg = firstIncompatibleTypeArg(tree.type); 1353 if (incompatibleArg != null) { 1354 for (JCTree arg : tree.arguments) { 1355 if (arg.type == incompatibleArg) { 1356 log.error(arg, Errors.NotWithinBounds(incompatibleArg, forms.head)); 1357 } 1358 forms = forms.tail; 1359 } 1360 } 1361 1362 forms = tree.type.tsym.type.getTypeArguments(); 1363 1364 boolean is_java_lang_Class = tree.type.tsym.flatName() == names.java_lang_Class; 1365 1366 // For matching pairs of actual argument types `a' and 1367 // formal type parameters with declared bound `b' ... 1368 while (args.nonEmpty() && forms.nonEmpty()) { 1369 validateTree(args.head, 1370 !(isOuter && is_java_lang_Class), 1371 false); 1372 args = args.tail; 1373 forms = forms.tail; 1374 } 1375 1376 // Check that this type is either fully parameterized, or 1377 // not parameterized at all. 1378 if (tree.type.getEnclosingType().isRaw()) 1379 log.error(tree.pos(), Errors.ImproperlyFormedTypeInnerRawParam); 1380 if (tree.clazz.hasTag(SELECT)) 1381 visitSelectInternal((JCFieldAccess)tree.clazz); 1382 } 1383 } 1384 1385 @Override 1386 public void visitTypeParameter(JCTypeParameter tree) { 1387 validateTrees(tree.bounds, true, isOuter); 1388 checkClassBounds(tree.pos(), tree.type); 1389 } 1390 1391 @Override 1392 public void visitWildcard(JCWildcard tree) { 1393 if (tree.inner != null) 1394 validateTree(tree.inner, true, isOuter); 1395 } 1396 1397 @Override 1398 public void visitSelect(JCFieldAccess tree) { 1399 if (tree.type.hasTag(CLASS)) { 1400 visitSelectInternal(tree); 1401 1402 // Check that this type is either fully parameterized, or 1403 // not parameterized at all. 1404 if (tree.selected.type.isParameterized() && tree.type.tsym.type.getTypeArguments().nonEmpty()) 1405 log.error(tree.pos(), Errors.ImproperlyFormedTypeParamMissing); 1406 } 1407 } 1408 1409 public void visitSelectInternal(JCFieldAccess tree) { 1410 if (tree.type.tsym.isStatic() && 1411 tree.selected.type.isParameterized()) { 1412 // The enclosing type is not a class, so we are 1413 // looking at a static member type. However, the 1414 // qualifying expression is parameterized. 1415 log.error(tree.pos(), Errors.CantSelectStaticClassFromParamType); 1416 } else { 1417 // otherwise validate the rest of the expression 1418 tree.selected.accept(this); 1419 } 1420 } 1421 1422 @Override 1423 public void visitAnnotatedType(JCAnnotatedType tree) { 1424 tree.underlyingType.accept(this); 1425 } 1426 1427 @Override 1428 public void visitTypeIdent(JCPrimitiveTypeTree that) { 1429 if (that.type.hasTag(TypeTag.VOID)) { 1430 log.error(that.pos(), Errors.VoidNotAllowedHere); 1431 } 1432 super.visitTypeIdent(that); 1433 } 1434 1435 /** Default visitor method: do nothing. 1436 */ 1437 @Override 1438 public void visitTree(JCTree tree) { 1439 } 1440 1441 public void validateTree(JCTree tree, boolean checkRaw, boolean isOuter) { 1442 if (tree != null) { 1443 boolean prevCheckRaw = this.checkRaw; 1444 this.checkRaw = checkRaw; 1445 this.isOuter = isOuter; 1446 1447 try { 1448 tree.accept(this); 1449 if (checkRaw) 1450 checkRaw(tree, env); 1451 } catch (CompletionFailure ex) { 1452 completionError(tree.pos(), ex); 1453 } finally { 1454 this.checkRaw = prevCheckRaw; 1455 } 1456 } 1457 } 1458 1459 public void validateTrees(List<? extends JCTree> trees, boolean checkRaw, boolean isOuter) { 1460 for (List<? extends JCTree> l = trees; l.nonEmpty(); l = l.tail) 1461 validateTree(l.head, checkRaw, isOuter); 1462 } 1463 } 1464 1465 void checkRaw(JCTree tree, Env<AttrContext> env) { 1466 if (tree.type.hasTag(CLASS) && 1467 !TreeInfo.isDiamond(tree) && 1468 !withinAnonConstr(env) && 1469 tree.type.isRaw()) { 1470 log.warning(tree.pos(), LintWarnings.RawClassUse(tree.type, tree.type.tsym.type)); 1471 } 1472 } 1473 //where 1474 private boolean withinAnonConstr(Env<AttrContext> env) { 1475 return env.enclClass.name.isEmpty() && 1476 env.enclMethod != null && env.enclMethod.name == names.init; 1477 } 1478 1479 /* ************************************************************************* 1480 * Exception checking 1481 **************************************************************************/ 1482 1483 /* The following methods treat classes as sets that contain 1484 * the class itself and all their subclasses 1485 */ 1486 1487 /** Is given type a subtype of some of the types in given list? 1488 */ 1489 boolean subset(Type t, List<Type> ts) { 1490 for (List<Type> l = ts; l.nonEmpty(); l = l.tail) 1491 if (types.isSubtype(t, l.head)) return true; 1492 return false; 1493 } 1494 1495 /** Is given type a subtype or supertype of 1496 * some of the types in given list? 1497 */ 1498 boolean intersects(Type t, List<Type> ts) { 1499 for (List<Type> l = ts; l.nonEmpty(); l = l.tail) 1500 if (types.isSubtype(t, l.head) || types.isSubtype(l.head, t)) return true; 1501 return false; 1502 } 1503 1504 /** Add type set to given type list, unless it is a subclass of some class 1505 * in the list. 1506 */ 1507 List<Type> incl(Type t, List<Type> ts) { 1508 return subset(t, ts) ? ts : excl(t, ts).prepend(t); 1509 } 1510 1511 /** Remove type set from type set list. 1512 */ 1513 List<Type> excl(Type t, List<Type> ts) { 1514 if (ts.isEmpty()) { 1515 return ts; 1516 } else { 1517 List<Type> ts1 = excl(t, ts.tail); 1518 if (types.isSubtype(ts.head, t)) return ts1; 1519 else if (ts1 == ts.tail) return ts; 1520 else return ts1.prepend(ts.head); 1521 } 1522 } 1523 1524 /** Form the union of two type set lists. 1525 */ 1526 List<Type> union(List<Type> ts1, List<Type> ts2) { 1527 List<Type> ts = ts1; 1528 for (List<Type> l = ts2; l.nonEmpty(); l = l.tail) 1529 ts = incl(l.head, ts); 1530 return ts; 1531 } 1532 1533 /** Form the difference of two type lists. 1534 */ 1535 List<Type> diff(List<Type> ts1, List<Type> ts2) { 1536 List<Type> ts = ts1; 1537 for (List<Type> l = ts2; l.nonEmpty(); l = l.tail) 1538 ts = excl(l.head, ts); 1539 return ts; 1540 } 1541 1542 /** Form the intersection of two type lists. 1543 */ 1544 public List<Type> intersect(List<Type> ts1, List<Type> ts2) { 1545 List<Type> ts = List.nil(); 1546 for (List<Type> l = ts1; l.nonEmpty(); l = l.tail) 1547 if (subset(l.head, ts2)) ts = incl(l.head, ts); 1548 for (List<Type> l = ts2; l.nonEmpty(); l = l.tail) 1549 if (subset(l.head, ts1)) ts = incl(l.head, ts); 1550 return ts; 1551 } 1552 1553 /** Is exc an exception symbol that need not be declared? 1554 */ 1555 boolean isUnchecked(ClassSymbol exc) { 1556 return 1557 exc.kind == ERR || 1558 exc.isSubClass(syms.errorType.tsym, types) || 1559 exc.isSubClass(syms.runtimeExceptionType.tsym, types); 1560 } 1561 1562 /** Is exc an exception type that need not be declared? 1563 */ 1564 boolean isUnchecked(Type exc) { 1565 return 1566 (exc.hasTag(TYPEVAR)) ? isUnchecked(types.supertype(exc)) : 1567 (exc.hasTag(CLASS)) ? isUnchecked((ClassSymbol)exc.tsym) : 1568 exc.hasTag(BOT); 1569 } 1570 1571 boolean isChecked(Type exc) { 1572 return !isUnchecked(exc); 1573 } 1574 1575 /** Same, but handling completion failures. 1576 */ 1577 boolean isUnchecked(DiagnosticPosition pos, Type exc) { 1578 try { 1579 return isUnchecked(exc); 1580 } catch (CompletionFailure ex) { 1581 completionError(pos, ex); 1582 return true; 1583 } 1584 } 1585 1586 /** Is exc handled by given exception list? 1587 */ 1588 boolean isHandled(Type exc, List<Type> handled) { 1589 return isUnchecked(exc) || subset(exc, handled); 1590 } 1591 1592 /** Return all exceptions in thrown list that are not in handled list. 1593 * @param thrown The list of thrown exceptions. 1594 * @param handled The list of handled exceptions. 1595 */ 1596 List<Type> unhandled(List<Type> thrown, List<Type> handled) { 1597 List<Type> unhandled = List.nil(); 1598 for (List<Type> l = thrown; l.nonEmpty(); l = l.tail) 1599 if (!isHandled(l.head, handled)) unhandled = unhandled.prepend(l.head); 1600 return unhandled; 1601 } 1602 1603 /* ************************************************************************* 1604 * Overriding/Implementation checking 1605 **************************************************************************/ 1606 1607 /** The level of access protection given by a flag set, 1608 * where PRIVATE is highest and PUBLIC is lowest. 1609 */ 1610 static int protection(long flags) { 1611 switch ((short)(flags & AccessFlags)) { 1612 case PRIVATE: return 3; 1613 case PROTECTED: return 1; 1614 default: 1615 case PUBLIC: return 0; 1616 case 0: return 2; 1617 } 1618 } 1619 1620 /** A customized "cannot override" error message. 1621 * @param m The overriding method. 1622 * @param other The overridden method. 1623 * @return An internationalized string. 1624 */ 1625 Fragment cannotOverride(MethodSymbol m, MethodSymbol other) { 1626 Symbol mloc = m.location(); 1627 Symbol oloc = other.location(); 1628 1629 if ((other.owner.flags() & INTERFACE) == 0) 1630 return Fragments.CantOverride(m, mloc, other, oloc); 1631 else if ((m.owner.flags() & INTERFACE) == 0) 1632 return Fragments.CantImplement(m, mloc, other, oloc); 1633 else 1634 return Fragments.ClashesWith(m, mloc, other, oloc); 1635 } 1636 1637 /** A customized "override" warning message. 1638 * @param m The overriding method. 1639 * @param other The overridden method. 1640 * @return An internationalized string. 1641 */ 1642 Fragment uncheckedOverrides(MethodSymbol m, MethodSymbol other) { 1643 Symbol mloc = m.location(); 1644 Symbol oloc = other.location(); 1645 1646 if ((other.owner.flags() & INTERFACE) == 0) 1647 return Fragments.UncheckedOverride(m, mloc, other, oloc); 1648 else if ((m.owner.flags() & INTERFACE) == 0) 1649 return Fragments.UncheckedImplement(m, mloc, other, oloc); 1650 else 1651 return Fragments.UncheckedClashWith(m, mloc, other, oloc); 1652 } 1653 1654 /** A customized "override" warning message. 1655 * @param m The overriding method. 1656 * @param other The overridden method. 1657 * @return An internationalized string. 1658 */ 1659 Fragment varargsOverrides(MethodSymbol m, MethodSymbol other) { 1660 Symbol mloc = m.location(); 1661 Symbol oloc = other.location(); 1662 1663 if ((other.owner.flags() & INTERFACE) == 0) 1664 return Fragments.VarargsOverride(m, mloc, other, oloc); 1665 else if ((m.owner.flags() & INTERFACE) == 0) 1666 return Fragments.VarargsImplement(m, mloc, other, oloc); 1667 else 1668 return Fragments.VarargsClashWith(m, mloc, other, oloc); 1669 } 1670 1671 /** Check that this method conforms with overridden method 'other'. 1672 * where `origin' is the class where checking started. 1673 * Complications: 1674 * (1) Do not check overriding of synthetic methods 1675 * (reason: they might be final). 1676 * todo: check whether this is still necessary. 1677 * (2) Admit the case where an interface proxy throws fewer exceptions 1678 * than the method it implements. Augment the proxy methods with the 1679 * undeclared exceptions in this case. 1680 * (3) When generics are enabled, admit the case where an interface proxy 1681 * has a result type 1682 * extended by the result type of the method it implements. 1683 * Change the proxies result type to the smaller type in this case. 1684 * 1685 * @param tree The tree from which positions 1686 * are extracted for errors. 1687 * @param m The overriding method. 1688 * @param other The overridden method. 1689 * @param origin The class of which the overriding method 1690 * is a member. 1691 */ 1692 void checkOverride(JCTree tree, 1693 MethodSymbol m, 1694 MethodSymbol other, 1695 ClassSymbol origin) { 1696 // Don't check overriding of synthetic methods or by bridge methods. 1697 if ((m.flags() & (SYNTHETIC|BRIDGE)) != 0 || (other.flags() & SYNTHETIC) != 0) { 1698 return; 1699 } 1700 1701 // Error if static method overrides instance method (JLS 8.4.8.2). 1702 if ((m.flags() & STATIC) != 0 && 1703 (other.flags() & STATIC) == 0) { 1704 log.error(TreeInfo.diagnosticPositionFor(m, tree), 1705 Errors.OverrideStatic(cannotOverride(m, other))); 1706 m.flags_field |= BAD_OVERRIDE; 1707 return; 1708 } 1709 1710 // Error if instance method overrides static or final 1711 // method (JLS 8.4.8.1). 1712 if ((other.flags() & FINAL) != 0 || 1713 (m.flags() & STATIC) == 0 && 1714 (other.flags() & STATIC) != 0) { 1715 log.error(TreeInfo.diagnosticPositionFor(m, tree), 1716 Errors.OverrideMeth(cannotOverride(m, other), 1717 asFlagSet(other.flags() & (FINAL | STATIC)))); 1718 m.flags_field |= BAD_OVERRIDE; 1719 return; 1720 } 1721 1722 if ((m.owner.flags() & ANNOTATION) != 0) { 1723 // handled in validateAnnotationMethod 1724 return; 1725 } 1726 1727 // Error if overriding method has weaker access (JLS 8.4.8.3). 1728 if (protection(m.flags()) > protection(other.flags())) { 1729 log.error(TreeInfo.diagnosticPositionFor(m, tree), 1730 (other.flags() & AccessFlags) == 0 ? 1731 Errors.OverrideWeakerAccess(cannotOverride(m, other), 1732 "package") : 1733 Errors.OverrideWeakerAccess(cannotOverride(m, other), 1734 asFlagSet(other.flags() & AccessFlags))); 1735 m.flags_field |= BAD_OVERRIDE; 1736 return; 1737 } 1738 1739 if (shouldCheckPreview(m, other, origin)) { 1740 checkPreview(TreeInfo.diagnosticPositionFor(m, tree), 1741 m, origin.type, other); 1742 } 1743 1744 Type mt = types.memberType(origin.type, m); 1745 Type ot = types.memberType(origin.type, other); 1746 // Error if overriding result type is different 1747 // (or, in the case of generics mode, not a subtype) of 1748 // overridden result type. We have to rename any type parameters 1749 // before comparing types. 1750 List<Type> mtvars = mt.getTypeArguments(); 1751 List<Type> otvars = ot.getTypeArguments(); 1752 Type mtres = mt.getReturnType(); 1753 Type otres = types.subst(ot.getReturnType(), otvars, mtvars); 1754 1755 overrideWarner.clear(); 1756 boolean resultTypesOK = 1757 types.returnTypeSubstitutable(mt, ot, otres, overrideWarner); 1758 if (!resultTypesOK) { 1759 if ((m.flags() & STATIC) != 0 && (other.flags() & STATIC) != 0) { 1760 log.error(TreeInfo.diagnosticPositionFor(m, tree), 1761 Errors.OverrideIncompatibleRet(Fragments.CantHide(m, m.location(), other, 1762 other.location()), mtres, otres)); 1763 m.flags_field |= BAD_OVERRIDE; 1764 } else { 1765 log.error(TreeInfo.diagnosticPositionFor(m, tree), 1766 Errors.OverrideIncompatibleRet(cannotOverride(m, other), mtres, otres)); 1767 m.flags_field |= BAD_OVERRIDE; 1768 } 1769 return; 1770 } else if (overrideWarner.hasNonSilentLint(LintCategory.UNCHECKED)) { 1771 warnUnchecked(TreeInfo.diagnosticPositionFor(m, tree), 1772 LintWarnings.OverrideUncheckedRet(uncheckedOverrides(m, other), mtres, otres)); 1773 } 1774 1775 // Error if overriding method throws an exception not reported 1776 // by overridden method. 1777 List<Type> otthrown = types.subst(ot.getThrownTypes(), otvars, mtvars); 1778 List<Type> unhandledErased = unhandled(mt.getThrownTypes(), types.erasure(otthrown)); 1779 List<Type> unhandledUnerased = unhandled(mt.getThrownTypes(), otthrown); 1780 if (unhandledErased.nonEmpty()) { 1781 log.error(TreeInfo.diagnosticPositionFor(m, tree), 1782 Errors.OverrideMethDoesntThrow(cannotOverride(m, other), unhandledUnerased.head)); 1783 m.flags_field |= BAD_OVERRIDE; 1784 return; 1785 } 1786 else if (unhandledUnerased.nonEmpty()) { 1787 warnUnchecked(TreeInfo.diagnosticPositionFor(m, tree), 1788 LintWarnings.OverrideUncheckedThrown(cannotOverride(m, other), unhandledUnerased.head)); 1789 return; 1790 } 1791 1792 // Optional warning if varargs don't agree 1793 if ((((m.flags() ^ other.flags()) & Flags.VARARGS) != 0)) { 1794 log.warning(TreeInfo.diagnosticPositionFor(m, tree), 1795 ((m.flags() & Flags.VARARGS) != 0) 1796 ? LintWarnings.OverrideVarargsMissing(varargsOverrides(m, other)) 1797 : LintWarnings.OverrideVarargsExtra(varargsOverrides(m, other))); 1798 } 1799 1800 // Warn if instance method overrides bridge method (compiler spec ??) 1801 if ((other.flags() & BRIDGE) != 0) { 1802 log.warning(TreeInfo.diagnosticPositionFor(m, tree), 1803 Warnings.OverrideBridge(uncheckedOverrides(m, other))); 1804 } 1805 1806 // Warn if a deprecated method overridden by a non-deprecated one. 1807 if (!isDeprecatedOverrideIgnorable(other, origin)) { 1808 checkDeprecated(() -> TreeInfo.diagnosticPositionFor(m, tree), m, other); 1809 } 1810 } 1811 // where 1812 private boolean shouldCheckPreview(MethodSymbol m, MethodSymbol other, ClassSymbol origin) { 1813 if (m.owner != origin || 1814 //performance - only do the expensive checks when the overridden method is a Preview API: 1815 ((other.flags() & PREVIEW_API) == 0 && 1816 (other.owner.flags() & PREVIEW_API) == 0)) { 1817 return false; 1818 } 1819 1820 for (Symbol s : types.membersClosure(origin.type, false).getSymbolsByName(m.name)) { 1821 if (m != s && m.overrides(s, origin, types, false)) { 1822 //only produce preview warnings or errors if "m" immediatelly overrides "other" 1823 //without intermediate overriding methods: 1824 return s == other; 1825 } 1826 } 1827 1828 return false; 1829 } 1830 private boolean isDeprecatedOverrideIgnorable(MethodSymbol m, ClassSymbol origin) { 1831 // If the method, m, is defined in an interface, then ignore the issue if the method 1832 // is only inherited via a supertype and also implemented in the supertype, 1833 // because in that case, we will rediscover the issue when examining the method 1834 // in the supertype. 1835 // If the method, m, is not defined in an interface, then the only time we need to 1836 // address the issue is when the method is the supertype implementation: any other 1837 // case, we will have dealt with when examining the supertype classes 1838 ClassSymbol mc = m.enclClass(); 1839 Type st = types.supertype(origin.type); 1840 if (!st.hasTag(CLASS)) 1841 return true; 1842 MethodSymbol stimpl = m.implementation((ClassSymbol)st.tsym, types, false); 1843 1844 if (mc != null && ((mc.flags() & INTERFACE) != 0)) { 1845 List<Type> intfs = types.interfaces(origin.type); 1846 return (intfs.contains(mc.type) ? false : (stimpl != null)); 1847 } 1848 else 1849 return (stimpl != m); 1850 } 1851 1852 1853 // used to check if there were any unchecked conversions 1854 Warner overrideWarner = new Warner(); 1855 1856 /** Check that a class does not inherit two concrete methods 1857 * with the same signature. 1858 * @param pos Position to be used for error reporting. 1859 * @param site The class type to be checked. 1860 */ 1861 public void checkCompatibleConcretes(DiagnosticPosition pos, Type site) { 1862 Type sup = types.supertype(site); 1863 if (!sup.hasTag(CLASS)) return; 1864 1865 for (Type t1 = sup; 1866 t1.hasTag(CLASS) && t1.tsym.type.isParameterized(); 1867 t1 = types.supertype(t1)) { 1868 for (Symbol s1 : t1.tsym.members().getSymbols(NON_RECURSIVE)) { 1869 if (s1.kind != MTH || 1870 (s1.flags() & (STATIC|SYNTHETIC|BRIDGE)) != 0 || 1871 !s1.isInheritedIn(site.tsym, types) || 1872 ((MethodSymbol)s1).implementation(site.tsym, 1873 types, 1874 true) != s1) 1875 continue; 1876 Type st1 = types.memberType(t1, s1); 1877 int s1ArgsLength = st1.getParameterTypes().length(); 1878 if (st1 == s1.type) continue; 1879 1880 for (Type t2 = sup; 1881 t2.hasTag(CLASS); 1882 t2 = types.supertype(t2)) { 1883 for (Symbol s2 : t2.tsym.members().getSymbolsByName(s1.name)) { 1884 if (s2 == s1 || 1885 s2.kind != MTH || 1886 (s2.flags() & (STATIC|SYNTHETIC|BRIDGE)) != 0 || 1887 s2.type.getParameterTypes().length() != s1ArgsLength || 1888 !s2.isInheritedIn(site.tsym, types) || 1889 ((MethodSymbol)s2).implementation(site.tsym, 1890 types, 1891 true) != s2) 1892 continue; 1893 Type st2 = types.memberType(t2, s2); 1894 if (types.overrideEquivalent(st1, st2)) 1895 log.error(pos, 1896 Errors.ConcreteInheritanceConflict(s1, t1, s2, t2, sup)); 1897 } 1898 } 1899 } 1900 } 1901 } 1902 1903 /** Check that classes (or interfaces) do not each define an abstract 1904 * method with same name and arguments but incompatible return types. 1905 * @param pos Position to be used for error reporting. 1906 * @param t1 The first argument type. 1907 * @param t2 The second argument type. 1908 */ 1909 public boolean checkCompatibleAbstracts(DiagnosticPosition pos, 1910 Type t1, 1911 Type t2, 1912 Type site) { 1913 if ((site.tsym.flags() & COMPOUND) != 0) { 1914 // special case for intersections: need to eliminate wildcards in supertypes 1915 t1 = types.capture(t1); 1916 t2 = types.capture(t2); 1917 } 1918 return firstIncompatibility(pos, t1, t2, site) == null; 1919 } 1920 1921 /** Return the first method which is defined with same args 1922 * but different return types in two given interfaces, or null if none 1923 * exists. 1924 * @param t1 The first type. 1925 * @param t2 The second type. 1926 * @param site The most derived type. 1927 * @return symbol from t2 that conflicts with one in t1. 1928 */ 1929 private Symbol firstIncompatibility(DiagnosticPosition pos, Type t1, Type t2, Type site) { 1930 Map<TypeSymbol,Type> interfaces1 = new HashMap<>(); 1931 closure(t1, interfaces1); 1932 Map<TypeSymbol,Type> interfaces2; 1933 if (t1 == t2) 1934 interfaces2 = interfaces1; 1935 else 1936 closure(t2, interfaces1, interfaces2 = new HashMap<>()); 1937 1938 for (Type t3 : interfaces1.values()) { 1939 for (Type t4 : interfaces2.values()) { 1940 Symbol s = firstDirectIncompatibility(pos, t3, t4, site); 1941 if (s != null) return s; 1942 } 1943 } 1944 return null; 1945 } 1946 1947 /** Compute all the supertypes of t, indexed by type symbol. */ 1948 private void closure(Type t, Map<TypeSymbol,Type> typeMap) { 1949 if (!t.hasTag(CLASS)) return; 1950 if (typeMap.put(t.tsym, t) == null) { 1951 closure(types.supertype(t), typeMap); 1952 for (Type i : types.interfaces(t)) 1953 closure(i, typeMap); 1954 } 1955 } 1956 1957 /** Compute all the supertypes of t, indexed by type symbol (except those in typesSkip). */ 1958 private void closure(Type t, Map<TypeSymbol,Type> typesSkip, Map<TypeSymbol,Type> typeMap) { 1959 if (!t.hasTag(CLASS)) return; 1960 if (typesSkip.get(t.tsym) != null) return; 1961 if (typeMap.put(t.tsym, t) == null) { 1962 closure(types.supertype(t), typesSkip, typeMap); 1963 for (Type i : types.interfaces(t)) 1964 closure(i, typesSkip, typeMap); 1965 } 1966 } 1967 1968 /** Return the first method in t2 that conflicts with a method from t1. */ 1969 private Symbol firstDirectIncompatibility(DiagnosticPosition pos, Type t1, Type t2, Type site) { 1970 for (Symbol s1 : t1.tsym.members().getSymbols(NON_RECURSIVE)) { 1971 Type st1 = null; 1972 if (s1.kind != MTH || !s1.isInheritedIn(site.tsym, types) || 1973 (s1.flags() & SYNTHETIC) != 0) continue; 1974 Symbol impl = ((MethodSymbol)s1).implementation(site.tsym, types, false); 1975 if (impl != null && (impl.flags() & ABSTRACT) == 0) continue; 1976 for (Symbol s2 : t2.tsym.members().getSymbolsByName(s1.name)) { 1977 if (s1 == s2) continue; 1978 if (s2.kind != MTH || !s2.isInheritedIn(site.tsym, types) || 1979 (s2.flags() & SYNTHETIC) != 0) continue; 1980 if (st1 == null) st1 = types.memberType(t1, s1); 1981 Type st2 = types.memberType(t2, s2); 1982 if (types.overrideEquivalent(st1, st2)) { 1983 List<Type> tvars1 = st1.getTypeArguments(); 1984 List<Type> tvars2 = st2.getTypeArguments(); 1985 Type rt1 = st1.getReturnType(); 1986 Type rt2 = types.subst(st2.getReturnType(), tvars2, tvars1); 1987 boolean compat = 1988 types.isSameType(rt1, rt2) || 1989 !rt1.isPrimitiveOrVoid() && 1990 !rt2.isPrimitiveOrVoid() && 1991 (types.covariantReturnType(rt1, rt2, types.noWarnings) || 1992 types.covariantReturnType(rt2, rt1, types.noWarnings)) || 1993 checkCommonOverriderIn(s1,s2,site); 1994 if (!compat) { 1995 if (types.isSameType(t1, t2)) { 1996 log.error(pos, Errors.IncompatibleDiffRetSameType(t1, 1997 s2.name, types.memberType(t2, s2).getParameterTypes())); 1998 } else { 1999 log.error(pos, Errors.TypesIncompatible(t1, t2, 2000 Fragments.IncompatibleDiffRet(s2.name, types.memberType(t2, s2).getParameterTypes()))); 2001 } 2002 return s2; 2003 } 2004 } else if (checkNameClash((ClassSymbol)site.tsym, s1, s2) && 2005 !checkCommonOverriderIn(s1, s2, site)) { 2006 log.error(pos, Errors.NameClashSameErasureNoOverride( 2007 s1.name, types.memberType(site, s1).asMethodType().getParameterTypes(), s1.location(), 2008 s2.name, types.memberType(site, s2).asMethodType().getParameterTypes(), s2.location())); 2009 return s2; 2010 } 2011 } 2012 } 2013 return null; 2014 } 2015 //WHERE 2016 boolean checkCommonOverriderIn(Symbol s1, Symbol s2, Type site) { 2017 Map<TypeSymbol,Type> supertypes = new HashMap<>(); 2018 Type st1 = types.memberType(site, s1); 2019 Type st2 = types.memberType(site, s2); 2020 closure(site, supertypes); 2021 for (Type t : supertypes.values()) { 2022 for (Symbol s3 : t.tsym.members().getSymbolsByName(s1.name)) { 2023 if (s3 == s1 || s3 == s2 || s3.kind != MTH || (s3.flags() & (BRIDGE|SYNTHETIC)) != 0) continue; 2024 Type st3 = types.memberType(site,s3); 2025 if (types.overrideEquivalent(st3, st1) && 2026 types.overrideEquivalent(st3, st2) && 2027 types.returnTypeSubstitutable(st3, st1) && 2028 types.returnTypeSubstitutable(st3, st2)) { 2029 return true; 2030 } 2031 } 2032 } 2033 return false; 2034 } 2035 2036 /** Check that a given method conforms with any method it overrides. 2037 * @param tree The tree from which positions are extracted 2038 * for errors. 2039 * @param m The overriding method. 2040 */ 2041 void checkOverride(Env<AttrContext> env, JCMethodDecl tree, MethodSymbol m) { 2042 ClassSymbol origin = (ClassSymbol)m.owner; 2043 if ((origin.flags() & ENUM) != 0 && names.finalize.equals(m.name)) { 2044 if (m.overrides(syms.enumFinalFinalize, origin, types, false)) { 2045 log.error(tree.pos(), Errors.EnumNoFinalize); 2046 return; 2047 } 2048 } 2049 if (allowRecords && origin.isRecord()) { 2050 // let's find out if this is a user defined accessor in which case the @Override annotation is acceptable 2051 Optional<? extends RecordComponent> recordComponent = origin.getRecordComponents().stream() 2052 .filter(rc -> rc.accessor == tree.sym && (rc.accessor.flags_field & GENERATED_MEMBER) == 0).findFirst(); 2053 if (recordComponent.isPresent()) { 2054 return; 2055 } 2056 } 2057 2058 for (Type t = origin.type; t.hasTag(CLASS); 2059 t = types.supertype(t)) { 2060 if (t != origin.type) { 2061 checkOverride(tree, t, origin, m); 2062 } 2063 for (Type t2 : types.interfaces(t)) { 2064 checkOverride(tree, t2, origin, m); 2065 } 2066 } 2067 2068 final boolean explicitOverride = m.attribute(syms.overrideType.tsym) != null; 2069 // Check if this method must override a super method due to being annotated with @Override 2070 // or by virtue of being a member of a diamond inferred anonymous class. Latter case is to 2071 // be treated "as if as they were annotated" with @Override. 2072 boolean mustOverride = explicitOverride || 2073 (env.info.isAnonymousDiamond && !m.isConstructor() && !m.isPrivate()); 2074 if (mustOverride && !isOverrider(m)) { 2075 DiagnosticPosition pos = tree.pos(); 2076 for (JCAnnotation a : tree.getModifiers().annotations) { 2077 if (a.annotationType.type.tsym == syms.overrideType.tsym) { 2078 pos = a.pos(); 2079 break; 2080 } 2081 } 2082 log.error(pos, 2083 explicitOverride ? (m.isStatic() ? Errors.StaticMethodsCannotBeAnnotatedWithOverride : Errors.MethodDoesNotOverrideSuperclass) : 2084 Errors.AnonymousDiamondMethodDoesNotOverrideSuperclass(Fragments.DiamondAnonymousMethodsImplicitlyOverride)); 2085 } 2086 } 2087 2088 void checkOverride(JCTree tree, Type site, ClassSymbol origin, MethodSymbol m) { 2089 TypeSymbol c = site.tsym; 2090 for (Symbol sym : c.members().getSymbolsByName(m.name)) { 2091 if (m.overrides(sym, origin, types, false)) { 2092 if ((sym.flags() & ABSTRACT) == 0) { 2093 checkOverride(tree, m, (MethodSymbol)sym, origin); 2094 } 2095 } 2096 } 2097 } 2098 2099 private Predicate<Symbol> equalsHasCodeFilter = s -> MethodSymbol.implementation_filter.test(s) && 2100 (s.flags() & BAD_OVERRIDE) == 0; 2101 2102 public void checkClassOverrideEqualsAndHashIfNeeded(DiagnosticPosition pos, 2103 ClassSymbol someClass) { 2104 /* At present, annotations cannot possibly have a method that is override 2105 * equivalent with Object.equals(Object) but in any case the condition is 2106 * fine for completeness. 2107 */ 2108 if (someClass == (ClassSymbol)syms.objectType.tsym || 2109 someClass.isInterface() || someClass.isEnum() || 2110 (someClass.flags() & ANNOTATION) != 0 || 2111 (someClass.flags() & ABSTRACT) != 0) return; 2112 //anonymous inner classes implementing interfaces need especial treatment 2113 if (someClass.isAnonymous()) { 2114 List<Type> interfaces = types.interfaces(someClass.type); 2115 if (interfaces != null && !interfaces.isEmpty() && 2116 interfaces.head.tsym == syms.comparatorType.tsym) return; 2117 } 2118 checkClassOverrideEqualsAndHash(pos, someClass); 2119 } 2120 2121 private void checkClassOverrideEqualsAndHash(DiagnosticPosition pos, 2122 ClassSymbol someClass) { 2123 if (lint.isEnabled(LintCategory.OVERRIDES)) { 2124 MethodSymbol equalsAtObject = (MethodSymbol)syms.objectType 2125 .tsym.members().findFirst(names.equals); 2126 MethodSymbol hashCodeAtObject = (MethodSymbol)syms.objectType 2127 .tsym.members().findFirst(names.hashCode); 2128 MethodSymbol equalsImpl = types.implementation(equalsAtObject, 2129 someClass, false, equalsHasCodeFilter); 2130 boolean overridesEquals = equalsImpl != null && 2131 equalsImpl.owner == someClass; 2132 boolean overridesHashCode = types.implementation(hashCodeAtObject, 2133 someClass, false, equalsHasCodeFilter) != hashCodeAtObject; 2134 2135 if (overridesEquals && !overridesHashCode) { 2136 log.warning(pos, 2137 LintWarnings.OverrideEqualsButNotHashcode(someClass)); 2138 } 2139 } 2140 } 2141 2142 public void checkHasMain(DiagnosticPosition pos, ClassSymbol c) { 2143 boolean found = false; 2144 2145 for (Symbol sym : c.members().getSymbolsByName(names.main)) { 2146 if (sym.kind == MTH && (sym.flags() & PRIVATE) == 0) { 2147 MethodSymbol meth = (MethodSymbol)sym; 2148 if (!types.isSameType(meth.getReturnType(), syms.voidType)) { 2149 continue; 2150 } 2151 if (meth.params.isEmpty()) { 2152 found = true; 2153 break; 2154 } 2155 if (meth.params.size() != 1) { 2156 continue; 2157 } 2158 if (!types.isSameType(meth.params.head.type, types.makeArrayType(syms.stringType))) { 2159 continue; 2160 } 2161 2162 found = true; 2163 break; 2164 } 2165 } 2166 2167 if (!found) { 2168 log.error(pos, Errors.ImplicitClassDoesNotHaveMainMethod); 2169 } 2170 } 2171 2172 public void checkModuleName (JCModuleDecl tree) { 2173 Name moduleName = tree.sym.name; 2174 Assert.checkNonNull(moduleName); 2175 if (lint.isEnabled(LintCategory.MODULE)) { 2176 JCExpression qualId = tree.qualId; 2177 while (qualId != null) { 2178 Name componentName; 2179 DiagnosticPosition pos; 2180 switch (qualId.getTag()) { 2181 case SELECT: 2182 JCFieldAccess selectNode = ((JCFieldAccess) qualId); 2183 componentName = selectNode.name; 2184 pos = selectNode.pos(); 2185 qualId = selectNode.selected; 2186 break; 2187 case IDENT: 2188 componentName = ((JCIdent) qualId).name; 2189 pos = qualId.pos(); 2190 qualId = null; 2191 break; 2192 default: 2193 throw new AssertionError("Unexpected qualified identifier: " + qualId.toString()); 2194 } 2195 if (componentName != null) { 2196 String moduleNameComponentString = componentName.toString(); 2197 int nameLength = moduleNameComponentString.length(); 2198 if (nameLength > 0 && Character.isDigit(moduleNameComponentString.charAt(nameLength - 1))) { 2199 log.warning(pos, LintWarnings.PoorChoiceForModuleName(componentName)); 2200 } 2201 } 2202 } 2203 } 2204 } 2205 2206 private boolean checkNameClash(ClassSymbol origin, Symbol s1, Symbol s2) { 2207 ClashFilter cf = new ClashFilter(origin.type); 2208 return (cf.test(s1) && 2209 cf.test(s2) && 2210 types.hasSameArgs(s1.erasure(types), s2.erasure(types))); 2211 } 2212 2213 2214 /** Check that all abstract members of given class have definitions. 2215 * @param pos Position to be used for error reporting. 2216 * @param c The class. 2217 */ 2218 void checkAllDefined(DiagnosticPosition pos, ClassSymbol c) { 2219 MethodSymbol undef = types.firstUnimplementedAbstract(c); 2220 if (undef != null) { 2221 MethodSymbol undef1 = 2222 new MethodSymbol(undef.flags(), undef.name, 2223 types.memberType(c.type, undef), undef.owner); 2224 log.error(pos, 2225 Errors.DoesNotOverrideAbstract(c, undef1, undef1.location())); 2226 } 2227 } 2228 2229 void checkNonCyclicDecl(JCClassDecl tree) { 2230 CycleChecker cc = new CycleChecker(); 2231 cc.scan(tree); 2232 if (!cc.errorFound && !cc.partialCheck) { 2233 tree.sym.flags_field |= ACYCLIC; 2234 } 2235 } 2236 2237 class CycleChecker extends TreeScanner { 2238 2239 Set<Symbol> seenClasses = new HashSet<>(); 2240 boolean errorFound = false; 2241 boolean partialCheck = false; 2242 2243 private void checkSymbol(DiagnosticPosition pos, Symbol sym) { 2244 if (sym != null && sym.kind == TYP) { 2245 Env<AttrContext> classEnv = enter.getEnv((TypeSymbol)sym); 2246 if (classEnv != null) { 2247 DiagnosticSource prevSource = log.currentSource(); 2248 try { 2249 log.useSource(classEnv.toplevel.sourcefile); 2250 scan(classEnv.tree); 2251 } 2252 finally { 2253 log.useSource(prevSource.getFile()); 2254 } 2255 } else if (sym.kind == TYP) { 2256 checkClass(pos, sym, List.nil()); 2257 } 2258 } else if (sym == null || sym.kind != PCK) { 2259 //not completed yet 2260 partialCheck = true; 2261 } 2262 } 2263 2264 @Override 2265 public void visitSelect(JCFieldAccess tree) { 2266 super.visitSelect(tree); 2267 checkSymbol(tree.pos(), tree.sym); 2268 } 2269 2270 @Override 2271 public void visitIdent(JCIdent tree) { 2272 checkSymbol(tree.pos(), tree.sym); 2273 } 2274 2275 @Override 2276 public void visitTypeApply(JCTypeApply tree) { 2277 scan(tree.clazz); 2278 } 2279 2280 @Override 2281 public void visitTypeArray(JCArrayTypeTree tree) { 2282 scan(tree.elemtype); 2283 } 2284 2285 @Override 2286 public void visitClassDef(JCClassDecl tree) { 2287 List<JCTree> supertypes = List.nil(); 2288 if (tree.getExtendsClause() != null) { 2289 supertypes = supertypes.prepend(tree.getExtendsClause()); 2290 } 2291 if (tree.getImplementsClause() != null) { 2292 for (JCTree intf : tree.getImplementsClause()) { 2293 supertypes = supertypes.prepend(intf); 2294 } 2295 } 2296 checkClass(tree.pos(), tree.sym, supertypes); 2297 } 2298 2299 void checkClass(DiagnosticPosition pos, Symbol c, List<JCTree> supertypes) { 2300 if ((c.flags_field & ACYCLIC) != 0) 2301 return; 2302 if (seenClasses.contains(c)) { 2303 errorFound = true; 2304 log.error(pos, Errors.CyclicInheritance(c)); 2305 seenClasses.stream() 2306 .filter(s -> !s.type.isErroneous()) 2307 .filter(ClassSymbol.class::isInstance) 2308 .map(ClassSymbol.class::cast) 2309 .forEach(Check.this::handleCyclic); 2310 } else if (!c.type.isErroneous()) { 2311 try { 2312 seenClasses.add(c); 2313 if (c.type.hasTag(CLASS)) { 2314 if (supertypes.nonEmpty()) { 2315 scan(supertypes); 2316 } 2317 else { 2318 ClassType ct = (ClassType)c.type; 2319 if (ct.supertype_field == null || 2320 ct.interfaces_field == null) { 2321 //not completed yet 2322 partialCheck = true; 2323 return; 2324 } 2325 checkSymbol(pos, ct.supertype_field.tsym); 2326 for (Type intf : ct.interfaces_field) { 2327 checkSymbol(pos, intf.tsym); 2328 } 2329 } 2330 if (c.owner.kind == TYP) { 2331 checkSymbol(pos, c.owner); 2332 } 2333 } 2334 } finally { 2335 seenClasses.remove(c); 2336 } 2337 } 2338 } 2339 } 2340 2341 /** Check for cyclic references. Issue an error if the 2342 * symbol of the type referred to has a LOCKED flag set. 2343 * 2344 * @param pos Position to be used for error reporting. 2345 * @param t The type referred to. 2346 */ 2347 void checkNonCyclic(DiagnosticPosition pos, Type t) { 2348 checkNonCyclicInternal(pos, t); 2349 } 2350 2351 2352 void checkNonCyclic(DiagnosticPosition pos, TypeVar t) { 2353 checkNonCyclic1(pos, t, List.nil()); 2354 } 2355 2356 private void checkNonCyclic1(DiagnosticPosition pos, Type t, List<TypeVar> seen) { 2357 final TypeVar tv; 2358 if (t.hasTag(TYPEVAR) && (t.tsym.flags() & UNATTRIBUTED) != 0) 2359 return; 2360 if (seen.contains(t)) { 2361 tv = (TypeVar)t; 2362 tv.setUpperBound(types.createErrorType(t)); 2363 log.error(pos, Errors.CyclicInheritance(t)); 2364 } else if (t.hasTag(TYPEVAR)) { 2365 tv = (TypeVar)t; 2366 seen = seen.prepend(tv); 2367 for (Type b : types.getBounds(tv)) 2368 checkNonCyclic1(pos, b, seen); 2369 } 2370 } 2371 2372 /** Check for cyclic references. Issue an error if the 2373 * symbol of the type referred to has a LOCKED flag set. 2374 * 2375 * @param pos Position to be used for error reporting. 2376 * @param t The type referred to. 2377 * @return True if the check completed on all attributed classes 2378 */ 2379 private boolean checkNonCyclicInternal(DiagnosticPosition pos, Type t) { 2380 boolean complete = true; // was the check complete? 2381 //- System.err.println("checkNonCyclicInternal("+t+");");//DEBUG 2382 Symbol c = t.tsym; 2383 if ((c.flags_field & ACYCLIC) != 0) return true; 2384 2385 if ((c.flags_field & LOCKED) != 0) { 2386 log.error(pos, Errors.CyclicInheritance(c)); 2387 handleCyclic((ClassSymbol)c); 2388 } else if (!c.type.isErroneous()) { 2389 try { 2390 c.flags_field |= LOCKED; 2391 if (c.type.hasTag(CLASS)) { 2392 ClassType clazz = (ClassType)c.type; 2393 if (clazz.interfaces_field != null) 2394 for (List<Type> l=clazz.interfaces_field; l.nonEmpty(); l=l.tail) 2395 complete &= checkNonCyclicInternal(pos, l.head); 2396 if (clazz.supertype_field != null) { 2397 Type st = clazz.supertype_field; 2398 if (st != null && st.hasTag(CLASS)) 2399 complete &= checkNonCyclicInternal(pos, st); 2400 } 2401 if (c.owner.kind == TYP) 2402 complete &= checkNonCyclicInternal(pos, c.owner.type); 2403 } 2404 } finally { 2405 c.flags_field &= ~LOCKED; 2406 } 2407 } 2408 if (complete) 2409 complete = ((c.flags_field & UNATTRIBUTED) == 0) && c.isCompleted(); 2410 if (complete) c.flags_field |= ACYCLIC; 2411 return complete; 2412 } 2413 2414 /** Handle finding an inheritance cycle on a class by setting 2415 * the class' and its supertypes' types to the error type. 2416 **/ 2417 private void handleCyclic(ClassSymbol c) { 2418 for (List<Type> l=types.interfaces(c.type); l.nonEmpty(); l=l.tail) 2419 l.head = types.createErrorType((ClassSymbol)l.head.tsym, Type.noType); 2420 Type st = types.supertype(c.type); 2421 if (st.hasTag(CLASS)) 2422 ((ClassType)c.type).supertype_field = types.createErrorType((ClassSymbol)st.tsym, Type.noType); 2423 c.type = types.createErrorType(c, c.type); 2424 c.flags_field |= ACYCLIC; 2425 } 2426 2427 /** Check that all methods which implement some 2428 * method conform to the method they implement. 2429 * @param tree The class definition whose members are checked. 2430 */ 2431 void checkImplementations(JCClassDecl tree) { 2432 checkImplementations(tree, tree.sym, tree.sym); 2433 } 2434 //where 2435 /** Check that all methods which implement some 2436 * method in `ic' conform to the method they implement. 2437 */ 2438 void checkImplementations(JCTree tree, ClassSymbol origin, ClassSymbol ic) { 2439 for (List<Type> l = types.closure(ic.type); l.nonEmpty(); l = l.tail) { 2440 ClassSymbol lc = (ClassSymbol)l.head.tsym; 2441 if ((lc.flags() & ABSTRACT) != 0) { 2442 for (Symbol sym : lc.members().getSymbols(NON_RECURSIVE)) { 2443 if (sym.kind == MTH && 2444 (sym.flags() & (STATIC|ABSTRACT)) == ABSTRACT) { 2445 MethodSymbol absmeth = (MethodSymbol)sym; 2446 MethodSymbol implmeth = absmeth.implementation(origin, types, false); 2447 if (implmeth != null && implmeth != absmeth && 2448 (implmeth.owner.flags() & INTERFACE) == 2449 (origin.flags() & INTERFACE)) { 2450 // don't check if implmeth is in a class, yet 2451 // origin is an interface. This case arises only 2452 // if implmeth is declared in Object. The reason is 2453 // that interfaces really don't inherit from 2454 // Object it's just that the compiler represents 2455 // things that way. 2456 checkOverride(tree, implmeth, absmeth, origin); 2457 } 2458 } 2459 } 2460 } 2461 } 2462 } 2463 2464 /** Check that all abstract methods implemented by a class are 2465 * mutually compatible. 2466 * @param pos Position to be used for error reporting. 2467 * @param c The class whose interfaces are checked. 2468 */ 2469 void checkCompatibleSupertypes(DiagnosticPosition pos, Type c) { 2470 List<Type> supertypes = types.interfaces(c); 2471 Type supertype = types.supertype(c); 2472 if (supertype.hasTag(CLASS) && 2473 (supertype.tsym.flags() & ABSTRACT) != 0) 2474 supertypes = supertypes.prepend(supertype); 2475 for (List<Type> l = supertypes; l.nonEmpty(); l = l.tail) { 2476 if (!l.head.getTypeArguments().isEmpty() && 2477 !checkCompatibleAbstracts(pos, l.head, l.head, c)) 2478 return; 2479 for (List<Type> m = supertypes; m != l; m = m.tail) 2480 if (!checkCompatibleAbstracts(pos, l.head, m.head, c)) 2481 return; 2482 } 2483 checkCompatibleConcretes(pos, c); 2484 } 2485 2486 /** Check that all non-override equivalent methods accessible from 'site' 2487 * are mutually compatible (JLS 8.4.8/9.4.1). 2488 * 2489 * @param pos Position to be used for error reporting. 2490 * @param site The class whose methods are checked. 2491 * @param sym The method symbol to be checked. 2492 */ 2493 void checkOverrideClashes(DiagnosticPosition pos, Type site, MethodSymbol sym) { 2494 ClashFilter cf = new ClashFilter(site); 2495 //for each method m1 that is overridden (directly or indirectly) 2496 //by method 'sym' in 'site'... 2497 2498 ArrayList<Symbol> symbolsByName = new ArrayList<>(); 2499 types.membersClosure(site, false).getSymbolsByName(sym.name, cf).forEach(symbolsByName::add); 2500 for (Symbol m1 : symbolsByName) { 2501 if (!sym.overrides(m1, site.tsym, types, false)) { 2502 continue; 2503 } 2504 2505 //...check each method m2 that is a member of 'site' 2506 for (Symbol m2 : symbolsByName) { 2507 if (m2 == m1) continue; 2508 //if (i) the signature of 'sym' is not a subsignature of m1 (seen as 2509 //a member of 'site') and (ii) m1 has the same erasure as m2, issue an error 2510 if (!types.isSubSignature(sym.type, types.memberType(site, m2)) && 2511 types.hasSameArgs(m2.erasure(types), m1.erasure(types))) { 2512 sym.flags_field |= CLASH; 2513 if (m1 == sym) { 2514 log.error(pos, Errors.NameClashSameErasureNoOverride( 2515 m1.name, types.memberType(site, m1).asMethodType().getParameterTypes(), m1.location(), 2516 m2.name, types.memberType(site, m2).asMethodType().getParameterTypes(), m2.location())); 2517 } else { 2518 ClassType ct = (ClassType)site; 2519 String kind = ct.isInterface() ? "interface" : "class"; 2520 log.error(pos, Errors.NameClashSameErasureNoOverride1( 2521 kind, 2522 ct.tsym.name, 2523 m1.name, 2524 types.memberType(site, m1).asMethodType().getParameterTypes(), 2525 m1.location(), 2526 m2.name, 2527 types.memberType(site, m2).asMethodType().getParameterTypes(), 2528 m2.location())); 2529 } 2530 return; 2531 } 2532 } 2533 } 2534 } 2535 2536 /** Check that all static methods accessible from 'site' are 2537 * mutually compatible (JLS 8.4.8). 2538 * 2539 * @param pos Position to be used for error reporting. 2540 * @param site The class whose methods are checked. 2541 * @param sym The method symbol to be checked. 2542 */ 2543 void checkHideClashes(DiagnosticPosition pos, Type site, MethodSymbol sym) { 2544 ClashFilter cf = new ClashFilter(site); 2545 //for each method m1 that is a member of 'site'... 2546 for (Symbol s : types.membersClosure(site, true).getSymbolsByName(sym.name, cf)) { 2547 //if (i) the signature of 'sym' is not a subsignature of m1 (seen as 2548 //a member of 'site') and (ii) 'sym' has the same erasure as m1, issue an error 2549 if (!types.isSubSignature(sym.type, types.memberType(site, s))) { 2550 if (types.hasSameArgs(s.erasure(types), sym.erasure(types))) { 2551 log.error(pos, 2552 Errors.NameClashSameErasureNoHide(sym, sym.location(), s, s.location())); 2553 return; 2554 } 2555 } 2556 } 2557 } 2558 2559 //where 2560 private class ClashFilter implements Predicate<Symbol> { 2561 2562 Type site; 2563 2564 ClashFilter(Type site) { 2565 this.site = site; 2566 } 2567 2568 boolean shouldSkip(Symbol s) { 2569 return (s.flags() & CLASH) != 0 && 2570 s.owner == site.tsym; 2571 } 2572 2573 @Override 2574 public boolean test(Symbol s) { 2575 return s.kind == MTH && 2576 (s.flags() & SYNTHETIC) == 0 && 2577 !shouldSkip(s) && 2578 s.isInheritedIn(site.tsym, types) && 2579 !s.isConstructor(); 2580 } 2581 } 2582 2583 void checkDefaultMethodClashes(DiagnosticPosition pos, Type site) { 2584 DefaultMethodClashFilter dcf = new DefaultMethodClashFilter(site); 2585 for (Symbol m : types.membersClosure(site, false).getSymbols(dcf)) { 2586 Assert.check(m.kind == MTH); 2587 List<MethodSymbol> prov = types.interfaceCandidates(site, (MethodSymbol)m); 2588 if (prov.size() > 1) { 2589 ListBuffer<Symbol> abstracts = new ListBuffer<>(); 2590 ListBuffer<Symbol> defaults = new ListBuffer<>(); 2591 for (MethodSymbol provSym : prov) { 2592 if ((provSym.flags() & DEFAULT) != 0) { 2593 defaults = defaults.append(provSym); 2594 } else if ((provSym.flags() & ABSTRACT) != 0) { 2595 abstracts = abstracts.append(provSym); 2596 } 2597 if (defaults.nonEmpty() && defaults.size() + abstracts.size() >= 2) { 2598 //strong semantics - issue an error if two sibling interfaces 2599 //have two override-equivalent defaults - or if one is abstract 2600 //and the other is default 2601 Fragment diagKey; 2602 Symbol s1 = defaults.first(); 2603 Symbol s2; 2604 if (defaults.size() > 1) { 2605 s2 = defaults.toList().tail.head; 2606 diagKey = Fragments.IncompatibleUnrelatedDefaults(Kinds.kindName(site.tsym), site, 2607 m.name, types.memberType(site, m).getParameterTypes(), 2608 s1.location(), s2.location()); 2609 2610 } else { 2611 s2 = abstracts.first(); 2612 diagKey = Fragments.IncompatibleAbstractDefault(Kinds.kindName(site.tsym), site, 2613 m.name, types.memberType(site, m).getParameterTypes(), 2614 s1.location(), s2.location()); 2615 } 2616 log.error(pos, Errors.TypesIncompatible(s1.location().type, s2.location().type, diagKey)); 2617 break; 2618 } 2619 } 2620 } 2621 } 2622 } 2623 2624 //where 2625 private class DefaultMethodClashFilter implements Predicate<Symbol> { 2626 2627 Type site; 2628 2629 DefaultMethodClashFilter(Type site) { 2630 this.site = site; 2631 } 2632 2633 @Override 2634 public boolean test(Symbol s) { 2635 return s.kind == MTH && 2636 (s.flags() & DEFAULT) != 0 && 2637 s.isInheritedIn(site.tsym, types) && 2638 !s.isConstructor(); 2639 } 2640 } 2641 2642 /** Report warnings for potentially ambiguous method declarations in the given site. */ 2643 void checkPotentiallyAmbiguousOverloads(JCClassDecl tree, Type site) { 2644 2645 // Skip if warning not enabled 2646 if (!lint.isEnabled(LintCategory.OVERLOADS)) 2647 return; 2648 2649 // Gather all of site's methods, including overridden methods, grouped by name (except Object methods) 2650 List<java.util.List<MethodSymbol>> methodGroups = methodsGroupedByName(site, 2651 new PotentiallyAmbiguousFilter(site), ArrayList::new); 2652 2653 // Build the predicate that determines if site is responsible for an ambiguity 2654 BiPredicate<MethodSymbol, MethodSymbol> responsible = buildResponsiblePredicate(site, methodGroups); 2655 2656 // Now remove overridden methods from each group, leaving only site's actual members 2657 methodGroups.forEach(list -> removePreempted(list, (m1, m2) -> m1.overrides(m2, site.tsym, types, false))); 2658 2659 // Allow site's own declared methods (only) to apply @SuppressWarnings("overloads") 2660 methodGroups.forEach(list -> list.removeIf( 2661 m -> m.owner == site.tsym && !lint.augment(m).isEnabled(LintCategory.OVERLOADS))); 2662 2663 // Warn about ambiguous overload method pairs for which site is responsible 2664 methodGroups.forEach(list -> compareAndRemove(list, (m1, m2) -> { 2665 2666 // See if this is an ambiguous overload for which "site" is responsible 2667 if (!potentiallyAmbiguousOverload(site, m1, m2) || !responsible.test(m1, m2)) 2668 return 0; 2669 2670 // Locate the warning at one of the methods, if possible 2671 DiagnosticPosition pos = 2672 m1.owner == site.tsym ? TreeInfo.diagnosticPositionFor(m1, tree) : 2673 m2.owner == site.tsym ? TreeInfo.diagnosticPositionFor(m2, tree) : 2674 tree.pos(); 2675 2676 // Log the warning 2677 log.warning(pos, 2678 LintWarnings.PotentiallyAmbiguousOverload( 2679 m1.asMemberOf(site, types), m1.location(), 2680 m2.asMemberOf(site, types), m2.location())); 2681 2682 // Don't warn again for either of these two methods 2683 return FIRST | SECOND; 2684 })); 2685 } 2686 2687 /** Build a predicate that determines, given two methods that are members of the given class, 2688 * whether the class should be held "responsible" if the methods are potentially ambiguous. 2689 * 2690 * Sometimes ambiguous methods are unavoidable because they're inherited from a supertype. 2691 * For example, any subtype of Spliterator.OfInt will have ambiguities for both 2692 * forEachRemaining() and tryAdvance() (in both cases the overloads are IntConsumer and 2693 * Consumer<? super Integer>). So we only want to "blame" a class when that class is 2694 * itself responsible for creating the ambiguity. We declare that a class C is "responsible" 2695 * for the ambiguity between two methods m1 and m2 if there is no direct supertype T of C 2696 * such that m1 and m2, or some overrides thereof, both exist in T and are ambiguous in T. 2697 * As an optimization, we first check if either method is declared in C and does not override 2698 * any other methods; in this case the class is definitely responsible. 2699 */ 2700 BiPredicate<MethodSymbol, MethodSymbol> buildResponsiblePredicate(Type site, 2701 List<? extends Collection<MethodSymbol>> methodGroups) { 2702 2703 // Define the "overrides" predicate 2704 BiPredicate<MethodSymbol, MethodSymbol> overrides = (m1, m2) -> m1.overrides(m2, site.tsym, types, false); 2705 2706 // Map each method declared in site to a list of the supertype method(s) it directly overrides 2707 HashMap<MethodSymbol, ArrayList<MethodSymbol>> overriddenMethodsMap = new HashMap<>(); 2708 methodGroups.forEach(list -> { 2709 for (MethodSymbol m : list) { 2710 2711 // Skip methods not declared in site 2712 if (m.owner != site.tsym) 2713 continue; 2714 2715 // Gather all supertype methods overridden by m, directly or indirectly 2716 ArrayList<MethodSymbol> overriddenMethods = list.stream() 2717 .filter(m2 -> m2 != m && overrides.test(m, m2)) 2718 .collect(Collectors.toCollection(ArrayList::new)); 2719 2720 // Eliminate non-direct overrides 2721 removePreempted(overriddenMethods, overrides); 2722 2723 // Add to map 2724 overriddenMethodsMap.put(m, overriddenMethods); 2725 } 2726 }); 2727 2728 // Build the predicate 2729 return (m1, m2) -> { 2730 2731 // Get corresponding supertype methods (if declared in site) 2732 java.util.List<MethodSymbol> overriddenMethods1 = overriddenMethodsMap.get(m1); 2733 java.util.List<MethodSymbol> overriddenMethods2 = overriddenMethodsMap.get(m2); 2734 2735 // Quick check for the case where a method was added by site itself 2736 if (overriddenMethods1 != null && overriddenMethods1.isEmpty()) 2737 return true; 2738 if (overriddenMethods2 != null && overriddenMethods2.isEmpty()) 2739 return true; 2740 2741 // Get each method's corresponding method(s) from supertypes of site 2742 java.util.List<MethodSymbol> supertypeMethods1 = overriddenMethods1 != null ? 2743 overriddenMethods1 : Collections.singletonList(m1); 2744 java.util.List<MethodSymbol> supertypeMethods2 = overriddenMethods2 != null ? 2745 overriddenMethods2 : Collections.singletonList(m2); 2746 2747 // See if we can blame some direct supertype instead 2748 return types.directSupertypes(site).stream() 2749 .filter(stype -> stype != syms.objectType) 2750 .map(stype -> stype.tsym.type) // view supertype in its original form 2751 .noneMatch(stype -> { 2752 for (MethodSymbol sm1 : supertypeMethods1) { 2753 if (!types.isSubtype(types.erasure(stype), types.erasure(sm1.owner.type))) 2754 continue; 2755 for (MethodSymbol sm2 : supertypeMethods2) { 2756 if (!types.isSubtype(types.erasure(stype), types.erasure(sm2.owner.type))) 2757 continue; 2758 if (potentiallyAmbiguousOverload(stype, sm1, sm2)) 2759 return true; 2760 } 2761 } 2762 return false; 2763 }); 2764 }; 2765 } 2766 2767 /** Gather all of site's methods, including overridden methods, grouped and sorted by name, 2768 * after applying the given filter. 2769 */ 2770 <C extends Collection<MethodSymbol>> List<C> methodsGroupedByName(Type site, 2771 Predicate<Symbol> filter, Supplier<? extends C> groupMaker) { 2772 Iterable<Symbol> symbols = types.membersClosure(site, false).getSymbols(filter, RECURSIVE); 2773 return StreamSupport.stream(symbols.spliterator(), false) 2774 .map(MethodSymbol.class::cast) 2775 .collect(Collectors.groupingBy(m -> m.name, Collectors.toCollection(groupMaker))) 2776 .entrySet() 2777 .stream() 2778 .sorted(Comparator.comparing(e -> e.getKey().toString())) 2779 .map(Map.Entry::getValue) 2780 .collect(List.collector()); 2781 } 2782 2783 /** Compare elements in a list pair-wise in order to remove some of them. 2784 * @param list mutable list of items 2785 * @param comparer returns flag bit(s) to remove FIRST and/or SECOND 2786 */ 2787 <T> void compareAndRemove(java.util.List<T> list, ToIntBiFunction<? super T, ? super T> comparer) { 2788 for (int index1 = 0; index1 < list.size() - 1; index1++) { 2789 T item1 = list.get(index1); 2790 for (int index2 = index1 + 1; index2 < list.size(); index2++) { 2791 T item2 = list.get(index2); 2792 int flags = comparer.applyAsInt(item1, item2); 2793 if ((flags & SECOND) != 0) 2794 list.remove(index2--); // remove item2 2795 if ((flags & FIRST) != 0) { 2796 list.remove(index1--); // remove item1 2797 break; 2798 } 2799 } 2800 } 2801 } 2802 2803 /** Remove elements in a list that are preempted by some other element in the list. 2804 * @param list mutable list of items 2805 * @param preempts decides if one item preempts another, causing the second one to be removed 2806 */ 2807 <T> void removePreempted(java.util.List<T> list, BiPredicate<? super T, ? super T> preempts) { 2808 compareAndRemove(list, (item1, item2) -> { 2809 int flags = 0; 2810 if (preempts.test(item1, item2)) 2811 flags |= SECOND; 2812 if (preempts.test(item2, item1)) 2813 flags |= FIRST; 2814 return flags; 2815 }); 2816 } 2817 2818 /** Filters method candidates for the "potentially ambiguous method" check */ 2819 class PotentiallyAmbiguousFilter extends ClashFilter { 2820 2821 PotentiallyAmbiguousFilter(Type site) { 2822 super(site); 2823 } 2824 2825 @Override 2826 boolean shouldSkip(Symbol s) { 2827 return s.owner.type.tsym == syms.objectType.tsym || super.shouldSkip(s); 2828 } 2829 } 2830 2831 /** 2832 * Report warnings for potentially ambiguous method declarations. Two declarations 2833 * are potentially ambiguous if they feature two unrelated functional interface 2834 * in same argument position (in which case, a call site passing an implicit 2835 * lambda would be ambiguous). This assumes they already have the same name. 2836 */ 2837 boolean potentiallyAmbiguousOverload(Type site, MethodSymbol msym1, MethodSymbol msym2) { 2838 Assert.check(msym1.name == msym2.name); 2839 if (msym1 == msym2) 2840 return false; 2841 Type mt1 = types.memberType(site, msym1); 2842 Type mt2 = types.memberType(site, msym2); 2843 //if both generic methods, adjust type variables 2844 if (mt1.hasTag(FORALL) && mt2.hasTag(FORALL) && 2845 types.hasSameBounds((ForAll)mt1, (ForAll)mt2)) { 2846 mt2 = types.subst(mt2, ((ForAll)mt2).tvars, ((ForAll)mt1).tvars); 2847 } 2848 //expand varargs methods if needed 2849 int maxLength = Math.max(mt1.getParameterTypes().length(), mt2.getParameterTypes().length()); 2850 List<Type> args1 = rs.adjustArgs(mt1.getParameterTypes(), msym1, maxLength, true); 2851 List<Type> args2 = rs.adjustArgs(mt2.getParameterTypes(), msym2, maxLength, true); 2852 //if arities don't match, exit 2853 if (args1.length() != args2.length()) 2854 return false; 2855 boolean potentiallyAmbiguous = false; 2856 while (args1.nonEmpty() && args2.nonEmpty()) { 2857 Type s = args1.head; 2858 Type t = args2.head; 2859 if (!types.isSubtype(t, s) && !types.isSubtype(s, t)) { 2860 if (types.isFunctionalInterface(s) && types.isFunctionalInterface(t) && 2861 types.findDescriptorType(s).getParameterTypes().length() > 0 && 2862 types.findDescriptorType(s).getParameterTypes().length() == 2863 types.findDescriptorType(t).getParameterTypes().length()) { 2864 potentiallyAmbiguous = true; 2865 } else { 2866 return false; 2867 } 2868 } 2869 args1 = args1.tail; 2870 args2 = args2.tail; 2871 } 2872 return potentiallyAmbiguous; 2873 } 2874 2875 // Apply special flag "-XDwarnOnAccessToMembers" which turns on just this particular warning for all types of access 2876 void checkAccessFromSerializableElement(final JCTree tree, boolean isLambda) { 2877 if (warnOnAnyAccessToMembers || isLambda) 2878 checkAccessFromSerializableElementInner(tree, isLambda); 2879 } 2880 2881 private void checkAccessFromSerializableElementInner(final JCTree tree, boolean isLambda) { 2882 Symbol sym = TreeInfo.symbol(tree); 2883 if (!sym.kind.matches(KindSelector.VAL_MTH)) { 2884 return; 2885 } 2886 2887 if (sym.kind == VAR) { 2888 if ((sym.flags() & PARAMETER) != 0 || 2889 sym.isDirectlyOrIndirectlyLocal() || 2890 sym.name == names._this || 2891 sym.name == names._super) { 2892 return; 2893 } 2894 } 2895 2896 if (!types.isSubtype(sym.owner.type, syms.serializableType) && isEffectivelyNonPublic(sym)) { 2897 DiagnosticFlag flag = warnOnAnyAccessToMembers ? DiagnosticFlag.DEFAULT_ENABLED : null; 2898 if (isLambda) { 2899 if (belongsToRestrictedPackage(sym)) { 2900 log.warning(flag, tree.pos(), LintWarnings.AccessToMemberFromSerializableLambda(sym)); 2901 } 2902 } else { 2903 log.warning(flag, tree.pos(), LintWarnings.AccessToMemberFromSerializableElement(sym)); 2904 } 2905 } 2906 } 2907 2908 private boolean isEffectivelyNonPublic(Symbol sym) { 2909 if (sym.packge() == syms.rootPackage) { 2910 return false; 2911 } 2912 2913 while (sym.kind != PCK) { 2914 if ((sym.flags() & PUBLIC) == 0) { 2915 return true; 2916 } 2917 sym = sym.owner; 2918 } 2919 return false; 2920 } 2921 2922 private boolean belongsToRestrictedPackage(Symbol sym) { 2923 String fullName = sym.packge().fullname.toString(); 2924 return fullName.startsWith("java.") || 2925 fullName.startsWith("javax.") || 2926 fullName.startsWith("sun.") || 2927 fullName.contains(".internal."); 2928 } 2929 2930 /** Check that class c does not implement directly or indirectly 2931 * the same parameterized interface with two different argument lists. 2932 * @param pos Position to be used for error reporting. 2933 * @param type The type whose interfaces are checked. 2934 */ 2935 void checkClassBounds(DiagnosticPosition pos, Type type) { 2936 checkClassBounds(pos, new HashMap<TypeSymbol,Type>(), type); 2937 } 2938 //where 2939 /** Enter all interfaces of type `type' into the hash table `seensofar' 2940 * with their class symbol as key and their type as value. Make 2941 * sure no class is entered with two different types. 2942 */ 2943 void checkClassBounds(DiagnosticPosition pos, 2944 Map<TypeSymbol,Type> seensofar, 2945 Type type) { 2946 if (type.isErroneous()) return; 2947 for (List<Type> l = types.interfaces(type); l.nonEmpty(); l = l.tail) { 2948 Type it = l.head; 2949 if (type.hasTag(CLASS) && !it.hasTag(CLASS)) continue; // JLS 8.1.5 2950 2951 Type oldit = seensofar.put(it.tsym, it); 2952 if (oldit != null) { 2953 List<Type> oldparams = oldit.allparams(); 2954 List<Type> newparams = it.allparams(); 2955 if (!types.containsTypeEquivalent(oldparams, newparams)) 2956 log.error(pos, 2957 Errors.CantInheritDiffArg(it.tsym, 2958 Type.toString(oldparams), 2959 Type.toString(newparams))); 2960 } 2961 checkClassBounds(pos, seensofar, it); 2962 } 2963 Type st = types.supertype(type); 2964 if (type.hasTag(CLASS) && !st.hasTag(CLASS)) return; // JLS 8.1.4 2965 if (st != Type.noType) checkClassBounds(pos, seensofar, st); 2966 } 2967 2968 /** Enter interface into into set. 2969 * If it existed already, issue a "repeated interface" error. 2970 */ 2971 void checkNotRepeated(DiagnosticPosition pos, Type it, Set<Symbol> its) { 2972 if (its.contains(it.tsym)) 2973 log.error(pos, Errors.RepeatedInterface); 2974 else { 2975 its.add(it.tsym); 2976 } 2977 } 2978 2979 /* ************************************************************************* 2980 * Check annotations 2981 **************************************************************************/ 2982 2983 /** 2984 * Recursively validate annotations values 2985 */ 2986 void validateAnnotationTree(JCTree tree) { 2987 class AnnotationValidator extends TreeScanner { 2988 @Override 2989 public void visitAnnotation(JCAnnotation tree) { 2990 if (!tree.type.isErroneous() && tree.type.tsym.isAnnotationType()) { 2991 super.visitAnnotation(tree); 2992 validateAnnotation(tree); 2993 } 2994 } 2995 } 2996 tree.accept(new AnnotationValidator()); 2997 } 2998 2999 /** 3000 * {@literal 3001 * Annotation types are restricted to primitives, String, an 3002 * enum, an annotation, Class, Class<?>, Class<? extends 3003 * Anything>, arrays of the preceding. 3004 * } 3005 */ 3006 void validateAnnotationType(JCTree restype) { 3007 // restype may be null if an error occurred, so don't bother validating it 3008 if (restype != null) { 3009 validateAnnotationType(restype.pos(), restype.type); 3010 } 3011 } 3012 3013 void validateAnnotationType(DiagnosticPosition pos, Type type) { 3014 if (type.isPrimitive()) return; 3015 if (types.isSameType(type, syms.stringType)) return; 3016 if ((type.tsym.flags() & Flags.ENUM) != 0) return; 3017 if ((type.tsym.flags() & Flags.ANNOTATION) != 0) return; 3018 if (types.cvarLowerBound(type).tsym == syms.classType.tsym) return; 3019 if (types.isArray(type) && !types.isArray(types.elemtype(type))) { 3020 validateAnnotationType(pos, types.elemtype(type)); 3021 return; 3022 } 3023 log.error(pos, Errors.InvalidAnnotationMemberType); 3024 } 3025 3026 /** 3027 * "It is also a compile-time error if any method declared in an 3028 * annotation type has a signature that is override-equivalent to 3029 * that of any public or protected method declared in class Object 3030 * or in the interface annotation.Annotation." 3031 * 3032 * @jls 9.6 Annotation Types 3033 */ 3034 void validateAnnotationMethod(DiagnosticPosition pos, MethodSymbol m) { 3035 for (Type sup = syms.annotationType; sup.hasTag(CLASS); sup = types.supertype(sup)) { 3036 Scope s = sup.tsym.members(); 3037 for (Symbol sym : s.getSymbolsByName(m.name)) { 3038 if (sym.kind == MTH && 3039 (sym.flags() & (PUBLIC | PROTECTED)) != 0 && 3040 types.overrideEquivalent(m.type, sym.type)) 3041 log.error(pos, Errors.IntfAnnotationMemberClash(sym, sup)); 3042 } 3043 } 3044 } 3045 3046 /** Check the annotations of a symbol. 3047 */ 3048 public void validateAnnotations(List<JCAnnotation> annotations, JCTree declarationTree, Symbol s) { 3049 for (JCAnnotation a : annotations) 3050 validateAnnotation(a, declarationTree, s); 3051 } 3052 3053 /** Check the type annotations. 3054 */ 3055 public void validateTypeAnnotations(List<JCAnnotation> annotations, Symbol s, boolean isTypeParameter) { 3056 for (JCAnnotation a : annotations) 3057 validateTypeAnnotation(a, s, isTypeParameter); 3058 } 3059 3060 /** Check an annotation of a symbol. 3061 */ 3062 private void validateAnnotation(JCAnnotation a, JCTree declarationTree, Symbol s) { 3063 /** NOTE: if annotation processors are present, annotation processing rounds can happen after this method, 3064 * this can impact in particular records for which annotations are forcibly propagated. 3065 */ 3066 validateAnnotationTree(a); 3067 boolean isRecordMember = ((s.flags_field & RECORD) != 0 || s.enclClass() != null && s.enclClass().isRecord()); 3068 3069 boolean isRecordField = (s.flags_field & RECORD) != 0 && 3070 declarationTree.hasTag(VARDEF) && 3071 s.owner.kind == TYP; 3072 3073 if (isRecordField) { 3074 // first we need to check if the annotation is applicable to records 3075 Name[] targets = getTargetNames(a); 3076 boolean appliesToRecords = false; 3077 for (Name target : targets) { 3078 appliesToRecords = 3079 target == names.FIELD || 3080 target == names.PARAMETER || 3081 target == names.METHOD || 3082 target == names.TYPE_USE || 3083 target == names.RECORD_COMPONENT; 3084 if (appliesToRecords) { 3085 break; 3086 } 3087 } 3088 if (!appliesToRecords) { 3089 log.error(a.pos(), Errors.AnnotationTypeNotApplicable); 3090 } else { 3091 /* lets now find the annotations in the field that are targeted to record components and append them to 3092 * the corresponding record component 3093 */ 3094 ClassSymbol recordClass = (ClassSymbol) s.owner; 3095 RecordComponent rc = recordClass.getRecordComponent((VarSymbol)s); 3096 SymbolMetadata metadata = rc.getMetadata(); 3097 if (metadata == null || metadata.isEmpty()) { 3098 /* if not is empty then we have already been here, which is the case if multiple annotations are applied 3099 * to the record component declaration 3100 */ 3101 rc.appendAttributes(s.getRawAttributes().stream().filter(anno -> 3102 Arrays.stream(getTargetNames(anno.type.tsym)).anyMatch(name -> name == names.RECORD_COMPONENT) 3103 ).collect(List.collector())); 3104 3105 JCVariableDecl fieldAST = (JCVariableDecl) declarationTree; 3106 for (JCAnnotation fieldAnnot : fieldAST.mods.annotations) { 3107 for (JCAnnotation rcAnnot : rc.declarationFor().mods.annotations) { 3108 if (rcAnnot.pos == fieldAnnot.pos) { 3109 rcAnnot.setType(fieldAnnot.type); 3110 break; 3111 } 3112 } 3113 } 3114 3115 /* At this point, we used to carry over any type annotations from the VARDEF to the record component, but 3116 * that is problematic, since we get here only when *some* annotation is applied to the SE5 (declaration) 3117 * annotation location, inadvertently failing to carry over the type annotations when the VarDef has no 3118 * annotations in the SE5 annotation location. 3119 * 3120 * Now type annotations are assigned to record components in a method that would execute irrespective of 3121 * whether there are SE5 annotations on a VarDef viz com.sun.tools.javac.code.TypeAnnotations.TypeAnnotationPositions.visitVarDef 3122 */ 3123 } 3124 } 3125 } 3126 3127 /* the section below is tricky. Annotations applied to record components are propagated to the corresponding 3128 * record member so if an annotation has target: FIELD, it is propagated to the corresponding FIELD, if it has 3129 * target METHOD, it is propagated to the accessor and so on. But at the moment when method members are generated 3130 * there is no enough information to propagate only the right annotations. So all the annotations are propagated 3131 * to all the possible locations. 3132 * 3133 * At this point we need to remove all the annotations that are not in place before going on with the annotation 3134 * party. On top of the above there is the issue that there is no AST representing record components, just symbols 3135 * so the corresponding field has been holding all the annotations and it's metadata has been modified as if it 3136 * was both a field and a record component. 3137 * 3138 * So there are two places where we need to trim annotations from: the metadata of the symbol and / or the modifiers 3139 * in the AST. Whatever is in the metadata will be written to the class file, whatever is in the modifiers could 3140 * be see by annotation processors. 3141 * 3142 * The metadata contains both type annotations and declaration annotations. At this point of the game we don't 3143 * need to care about type annotations, they are all in the right place. But we could need to remove declaration 3144 * annotations. So for declaration annotations if they are not applicable to the record member, excluding type 3145 * annotations which are already correct, then we will remove it. For the AST modifiers if the annotation is not 3146 * applicable either as type annotation and or declaration annotation, only in that case it will be removed. 3147 * 3148 * So it could be that annotation is removed as a declaration annotation but it is kept in the AST modifier for 3149 * further inspection by annotation processors. 3150 * 3151 * For example: 3152 * 3153 * import java.lang.annotation.*; 3154 * 3155 * @Target({ElementType.TYPE_USE, ElementType.RECORD_COMPONENT}) 3156 * @Retention(RetentionPolicy.RUNTIME) 3157 * @interface Anno { } 3158 * 3159 * record R(@Anno String s) {} 3160 * 3161 * at this point we will have for the case of the generated field: 3162 * - @Anno in the modifier 3163 * - @Anno as a type annotation 3164 * - @Anno as a declaration annotation 3165 * 3166 * the last one should be removed because the annotation has not FIELD as target but it was applied as a 3167 * declaration annotation because the field was being treated both as a field and as a record component 3168 * as we have already copied the annotations to the record component, now the field doesn't need to hold 3169 * annotations that are not intended for it anymore. Still @Anno has to be kept in the AST's modifiers as it 3170 * is applicable as a type annotation to the type of the field. 3171 */ 3172 3173 if (a.type.tsym.isAnnotationType()) { 3174 Optional<Set<Name>> applicableTargetsOp = getApplicableTargets(a, s); 3175 if (!applicableTargetsOp.isEmpty()) { 3176 Set<Name> applicableTargets = applicableTargetsOp.get(); 3177 boolean notApplicableOrIsTypeUseOnly = applicableTargets.isEmpty() || 3178 applicableTargets.size() == 1 && applicableTargets.contains(names.TYPE_USE); 3179 boolean isCompGeneratedRecordElement = isRecordMember && (s.flags_field & Flags.GENERATED_MEMBER) != 0; 3180 boolean isCompRecordElementWithNonApplicableDeclAnno = isCompGeneratedRecordElement && notApplicableOrIsTypeUseOnly; 3181 3182 if (applicableTargets.isEmpty() || isCompRecordElementWithNonApplicableDeclAnno) { 3183 if (isCompRecordElementWithNonApplicableDeclAnno) { 3184 /* so we have found an annotation that is not applicable to a record member that was generated by the 3185 * compiler. This was intentionally done at TypeEnter, now is the moment strip away the annotations 3186 * that are not applicable to the given record member 3187 */ 3188 JCModifiers modifiers = TreeInfo.getModifiers(declarationTree); 3189 /* lets first remove the annotation from the modifier if it is not applicable, we have to check again as 3190 * it could be a type annotation 3191 */ 3192 if (modifiers != null && applicableTargets.isEmpty()) { 3193 ListBuffer<JCAnnotation> newAnnotations = new ListBuffer<>(); 3194 for (JCAnnotation anno : modifiers.annotations) { 3195 if (anno != a) { 3196 newAnnotations.add(anno); 3197 } 3198 } 3199 modifiers.annotations = newAnnotations.toList(); 3200 } 3201 // now lets remove it from the symbol 3202 s.getMetadata().removeDeclarationMetadata(a.attribute); 3203 } else { 3204 log.error(a.pos(), Errors.AnnotationTypeNotApplicable); 3205 } 3206 } 3207 /* if we are seeing the @SafeVarargs annotation applied to a compiler generated accessor, 3208 * then this is an error as we know that no compiler generated accessor will be a varargs 3209 * method, better to fail asap 3210 */ 3211 if (isCompGeneratedRecordElement && !isRecordField && a.type.tsym == syms.trustMeType.tsym && declarationTree.hasTag(METHODDEF)) { 3212 log.error(a.pos(), Errors.VarargsInvalidTrustmeAnno(syms.trustMeType.tsym, Fragments.VarargsTrustmeOnNonVarargsAccessor(s))); 3213 } 3214 } 3215 } 3216 3217 if (a.annotationType.type.tsym == syms.functionalInterfaceType.tsym) { 3218 if (s.kind != TYP) { 3219 log.error(a.pos(), Errors.BadFunctionalIntfAnno); 3220 } else if (!s.isInterface() || (s.flags() & ANNOTATION) != 0) { 3221 log.error(a.pos(), Errors.BadFunctionalIntfAnno1(Fragments.NotAFunctionalIntf(s))); 3222 } 3223 } 3224 } 3225 3226 public void validateTypeAnnotation(JCAnnotation a, Symbol s, boolean isTypeParameter) { 3227 Assert.checkNonNull(a.type); 3228 // we just want to validate that the anotation doesn't have any wrong target 3229 if (s != null) getApplicableTargets(a, s); 3230 validateAnnotationTree(a); 3231 3232 if (a.hasTag(TYPE_ANNOTATION) && 3233 !a.annotationType.type.isErroneous() && 3234 !isTypeAnnotation(a, isTypeParameter)) { 3235 log.error(a.pos(), Errors.AnnotationTypeNotApplicableToType(a.type)); 3236 } 3237 } 3238 3239 /** 3240 * Validate the proposed container 'repeatable' on the 3241 * annotation type symbol 's'. Report errors at position 3242 * 'pos'. 3243 * 3244 * @param s The (annotation)type declaration annotated with a @Repeatable 3245 * @param repeatable the @Repeatable on 's' 3246 * @param pos where to report errors 3247 */ 3248 public void validateRepeatable(TypeSymbol s, Attribute.Compound repeatable, DiagnosticPosition pos) { 3249 Assert.check(types.isSameType(repeatable.type, syms.repeatableType)); 3250 3251 Type t = null; 3252 List<Pair<MethodSymbol,Attribute>> l = repeatable.values; 3253 if (!l.isEmpty()) { 3254 Assert.check(l.head.fst.name == names.value); 3255 if (l.head.snd instanceof Attribute.Class) { 3256 t = ((Attribute.Class)l.head.snd).getValue(); 3257 } 3258 } 3259 3260 if (t == null) { 3261 // errors should already have been reported during Annotate 3262 return; 3263 } 3264 3265 validateValue(t.tsym, s, pos); 3266 validateRetention(t.tsym, s, pos); 3267 validateDocumented(t.tsym, s, pos); 3268 validateInherited(t.tsym, s, pos); 3269 validateTarget(t.tsym, s, pos); 3270 validateDefault(t.tsym, pos); 3271 } 3272 3273 private void validateValue(TypeSymbol container, TypeSymbol contained, DiagnosticPosition pos) { 3274 Symbol sym = container.members().findFirst(names.value); 3275 if (sym != null && sym.kind == MTH) { 3276 MethodSymbol m = (MethodSymbol) sym; 3277 Type ret = m.getReturnType(); 3278 if (!(ret.hasTag(ARRAY) && types.isSameType(((ArrayType)ret).elemtype, contained.type))) { 3279 log.error(pos, 3280 Errors.InvalidRepeatableAnnotationValueReturn(container, 3281 ret, 3282 types.makeArrayType(contained.type))); 3283 } 3284 } else { 3285 log.error(pos, Errors.InvalidRepeatableAnnotationNoValue(container)); 3286 } 3287 } 3288 3289 private void validateRetention(TypeSymbol container, TypeSymbol contained, DiagnosticPosition pos) { 3290 Attribute.RetentionPolicy containerRetention = types.getRetention(container); 3291 Attribute.RetentionPolicy containedRetention = types.getRetention(contained); 3292 3293 boolean error = false; 3294 switch (containedRetention) { 3295 case RUNTIME: 3296 if (containerRetention != Attribute.RetentionPolicy.RUNTIME) { 3297 error = true; 3298 } 3299 break; 3300 case CLASS: 3301 if (containerRetention == Attribute.RetentionPolicy.SOURCE) { 3302 error = true; 3303 } 3304 } 3305 if (error ) { 3306 log.error(pos, 3307 Errors.InvalidRepeatableAnnotationRetention(container, 3308 containerRetention.name(), 3309 contained, 3310 containedRetention.name())); 3311 } 3312 } 3313 3314 private void validateDocumented(Symbol container, Symbol contained, DiagnosticPosition pos) { 3315 if (contained.attribute(syms.documentedType.tsym) != null) { 3316 if (container.attribute(syms.documentedType.tsym) == null) { 3317 log.error(pos, Errors.InvalidRepeatableAnnotationNotDocumented(container, contained)); 3318 } 3319 } 3320 } 3321 3322 private void validateInherited(Symbol container, Symbol contained, DiagnosticPosition pos) { 3323 if (contained.attribute(syms.inheritedType.tsym) != null) { 3324 if (container.attribute(syms.inheritedType.tsym) == null) { 3325 log.error(pos, Errors.InvalidRepeatableAnnotationNotInherited(container, contained)); 3326 } 3327 } 3328 } 3329 3330 private void validateTarget(TypeSymbol container, TypeSymbol contained, DiagnosticPosition pos) { 3331 // The set of targets the container is applicable to must be a subset 3332 // (with respect to annotation target semantics) of the set of targets 3333 // the contained is applicable to. The target sets may be implicit or 3334 // explicit. 3335 3336 Set<Name> containerTargets; 3337 Attribute.Array containerTarget = getAttributeTargetAttribute(container); 3338 if (containerTarget == null) { 3339 containerTargets = getDefaultTargetSet(); 3340 } else { 3341 containerTargets = new HashSet<>(); 3342 for (Attribute app : containerTarget.values) { 3343 if (!(app instanceof Attribute.Enum attributeEnum)) { 3344 continue; // recovery 3345 } 3346 containerTargets.add(attributeEnum.value.name); 3347 } 3348 } 3349 3350 Set<Name> containedTargets; 3351 Attribute.Array containedTarget = getAttributeTargetAttribute(contained); 3352 if (containedTarget == null) { 3353 containedTargets = getDefaultTargetSet(); 3354 } else { 3355 containedTargets = new HashSet<>(); 3356 for (Attribute app : containedTarget.values) { 3357 if (!(app instanceof Attribute.Enum attributeEnum)) { 3358 continue; // recovery 3359 } 3360 containedTargets.add(attributeEnum.value.name); 3361 } 3362 } 3363 3364 if (!isTargetSubsetOf(containerTargets, containedTargets)) { 3365 log.error(pos, Errors.InvalidRepeatableAnnotationIncompatibleTarget(container, contained)); 3366 } 3367 } 3368 3369 /* get a set of names for the default target */ 3370 private Set<Name> getDefaultTargetSet() { 3371 if (defaultTargets == null) { 3372 defaultTargets = Set.of(defaultTargetMetaInfo()); 3373 } 3374 3375 return defaultTargets; 3376 } 3377 private Set<Name> defaultTargets; 3378 3379 3380 /** Checks that s is a subset of t, with respect to ElementType 3381 * semantics, specifically {ANNOTATION_TYPE} is a subset of {TYPE}, 3382 * and {TYPE_USE} covers the set {ANNOTATION_TYPE, TYPE, TYPE_USE, 3383 * TYPE_PARAMETER}. 3384 */ 3385 private boolean isTargetSubsetOf(Set<Name> s, Set<Name> t) { 3386 // Check that all elements in s are present in t 3387 for (Name n2 : s) { 3388 boolean currentElementOk = false; 3389 for (Name n1 : t) { 3390 if (n1 == n2) { 3391 currentElementOk = true; 3392 break; 3393 } else if (n1 == names.TYPE && n2 == names.ANNOTATION_TYPE) { 3394 currentElementOk = true; 3395 break; 3396 } else if (n1 == names.TYPE_USE && 3397 (n2 == names.TYPE || 3398 n2 == names.ANNOTATION_TYPE || 3399 n2 == names.TYPE_PARAMETER)) { 3400 currentElementOk = true; 3401 break; 3402 } 3403 } 3404 if (!currentElementOk) 3405 return false; 3406 } 3407 return true; 3408 } 3409 3410 private void validateDefault(Symbol container, DiagnosticPosition pos) { 3411 // validate that all other elements of containing type has defaults 3412 Scope scope = container.members(); 3413 for(Symbol elm : scope.getSymbols()) { 3414 if (elm.name != names.value && 3415 elm.kind == MTH && 3416 ((MethodSymbol)elm).defaultValue == null) { 3417 log.error(pos, 3418 Errors.InvalidRepeatableAnnotationElemNondefault(container, elm)); 3419 } 3420 } 3421 } 3422 3423 /** Is s a method symbol that overrides a method in a superclass? */ 3424 boolean isOverrider(Symbol s) { 3425 if (s.kind != MTH || s.isStatic()) 3426 return false; 3427 MethodSymbol m = (MethodSymbol)s; 3428 TypeSymbol owner = (TypeSymbol)m.owner; 3429 for (Type sup : types.closure(owner.type)) { 3430 if (sup == owner.type) 3431 continue; // skip "this" 3432 Scope scope = sup.tsym.members(); 3433 for (Symbol sym : scope.getSymbolsByName(m.name)) { 3434 if (!sym.isStatic() && m.overrides(sym, owner, types, true)) 3435 return true; 3436 } 3437 } 3438 return false; 3439 } 3440 3441 /** Is the annotation applicable to types? */ 3442 protected boolean isTypeAnnotation(JCAnnotation a, boolean isTypeParameter) { 3443 List<Attribute> targets = typeAnnotations.annotationTargets(a.annotationType.type.tsym); 3444 return (targets == null) ? 3445 (Feature.NO_TARGET_ANNOTATION_APPLICABILITY.allowedInSource(source) && isTypeParameter) : 3446 targets.stream() 3447 .anyMatch(attr -> isTypeAnnotation(attr, isTypeParameter)); 3448 } 3449 //where 3450 boolean isTypeAnnotation(Attribute a, boolean isTypeParameter) { 3451 Attribute.Enum e = (Attribute.Enum)a; 3452 return (e.value.name == names.TYPE_USE || 3453 (isTypeParameter && e.value.name == names.TYPE_PARAMETER)); 3454 } 3455 3456 /** Is the annotation applicable to the symbol? */ 3457 Name[] getTargetNames(JCAnnotation a) { 3458 return getTargetNames(a.annotationType.type.tsym); 3459 } 3460 3461 public Name[] getTargetNames(TypeSymbol annoSym) { 3462 Attribute.Array arr = getAttributeTargetAttribute(annoSym); 3463 Name[] targets; 3464 if (arr == null) { 3465 targets = defaultTargetMetaInfo(); 3466 } else { 3467 // TODO: can we optimize this? 3468 targets = new Name[arr.values.length]; 3469 for (int i=0; i<arr.values.length; ++i) { 3470 Attribute app = arr.values[i]; 3471 if (!(app instanceof Attribute.Enum attributeEnum)) { 3472 return new Name[0]; 3473 } 3474 targets[i] = attributeEnum.value.name; 3475 } 3476 } 3477 return targets; 3478 } 3479 3480 boolean annotationApplicable(JCAnnotation a, Symbol s) { 3481 Optional<Set<Name>> targets = getApplicableTargets(a, s); 3482 /* the optional could be empty if the annotation is unknown in that case 3483 * we return that it is applicable and if it is erroneous that should imply 3484 * an error at the declaration site 3485 */ 3486 return targets.isEmpty() || targets.isPresent() && !targets.get().isEmpty(); 3487 } 3488 3489 Optional<Set<Name>> getApplicableTargets(JCAnnotation a, Symbol s) { 3490 Attribute.Array arr = getAttributeTargetAttribute(a.annotationType.type.tsym); 3491 Name[] targets; 3492 Set<Name> applicableTargets = new HashSet<>(); 3493 3494 if (arr == null) { 3495 targets = defaultTargetMetaInfo(); 3496 } else { 3497 // TODO: can we optimize this? 3498 targets = new Name[arr.values.length]; 3499 for (int i=0; i<arr.values.length; ++i) { 3500 Attribute app = arr.values[i]; 3501 if (!(app instanceof Attribute.Enum attributeEnum)) { 3502 // recovery 3503 return Optional.empty(); 3504 } 3505 targets[i] = attributeEnum.value.name; 3506 } 3507 } 3508 for (Name target : targets) { 3509 if (target == names.TYPE) { 3510 if (s.kind == TYP) 3511 applicableTargets.add(names.TYPE); 3512 } else if (target == names.FIELD) { 3513 if (s.kind == VAR && s.owner.kind != MTH) 3514 applicableTargets.add(names.FIELD); 3515 } else if (target == names.RECORD_COMPONENT) { 3516 if (s.getKind() == ElementKind.RECORD_COMPONENT) { 3517 applicableTargets.add(names.RECORD_COMPONENT); 3518 } 3519 } else if (target == names.METHOD) { 3520 if (s.kind == MTH && !s.isConstructor()) 3521 applicableTargets.add(names.METHOD); 3522 } else if (target == names.PARAMETER) { 3523 if (s.kind == VAR && 3524 (s.owner.kind == MTH && (s.flags() & PARAMETER) != 0)) { 3525 applicableTargets.add(names.PARAMETER); 3526 } 3527 } else if (target == names.CONSTRUCTOR) { 3528 if (s.kind == MTH && s.isConstructor()) 3529 applicableTargets.add(names.CONSTRUCTOR); 3530 } else if (target == names.LOCAL_VARIABLE) { 3531 if (s.kind == VAR && s.owner.kind == MTH && 3532 (s.flags() & PARAMETER) == 0) { 3533 applicableTargets.add(names.LOCAL_VARIABLE); 3534 } 3535 } else if (target == names.ANNOTATION_TYPE) { 3536 if (s.kind == TYP && (s.flags() & ANNOTATION) != 0) { 3537 applicableTargets.add(names.ANNOTATION_TYPE); 3538 } 3539 } else if (target == names.PACKAGE) { 3540 if (s.kind == PCK) 3541 applicableTargets.add(names.PACKAGE); 3542 } else if (target == names.TYPE_USE) { 3543 if (s.kind == VAR && s.owner.kind == MTH && s.type.hasTag(NONE)) { 3544 //cannot type annotate implicitly typed locals 3545 continue; 3546 } else if (s.kind == TYP || s.kind == VAR || 3547 (s.kind == MTH && !s.isConstructor() && 3548 !s.type.getReturnType().hasTag(VOID)) || 3549 (s.kind == MTH && s.isConstructor())) { 3550 applicableTargets.add(names.TYPE_USE); 3551 } 3552 } else if (target == names.TYPE_PARAMETER) { 3553 if (s.kind == TYP && s.type.hasTag(TYPEVAR)) 3554 applicableTargets.add(names.TYPE_PARAMETER); 3555 } else if (target == names.MODULE) { 3556 if (s.kind == MDL) 3557 applicableTargets.add(names.MODULE); 3558 } else { 3559 log.error(a, Errors.AnnotationUnrecognizedAttributeName(a.type, target)); 3560 return Optional.empty(); // Unknown ElementType 3561 } 3562 } 3563 return Optional.of(applicableTargets); 3564 } 3565 3566 Attribute.Array getAttributeTargetAttribute(TypeSymbol s) { 3567 Attribute.Compound atTarget = s.getAnnotationTypeMetadata().getTarget(); 3568 if (atTarget == null) return null; // ok, is applicable 3569 Attribute atValue = atTarget.member(names.value); 3570 return (atValue instanceof Attribute.Array attributeArray) ? attributeArray : null; 3571 } 3572 3573 private Name[] dfltTargetMeta; 3574 private Name[] defaultTargetMetaInfo() { 3575 if (dfltTargetMeta == null) { 3576 ArrayList<Name> defaultTargets = new ArrayList<>(); 3577 defaultTargets.add(names.PACKAGE); 3578 defaultTargets.add(names.TYPE); 3579 defaultTargets.add(names.FIELD); 3580 defaultTargets.add(names.METHOD); 3581 defaultTargets.add(names.CONSTRUCTOR); 3582 defaultTargets.add(names.ANNOTATION_TYPE); 3583 defaultTargets.add(names.LOCAL_VARIABLE); 3584 defaultTargets.add(names.PARAMETER); 3585 if (allowRecords) { 3586 defaultTargets.add(names.RECORD_COMPONENT); 3587 } 3588 if (allowModules) { 3589 defaultTargets.add(names.MODULE); 3590 } 3591 dfltTargetMeta = defaultTargets.toArray(new Name[0]); 3592 } 3593 return dfltTargetMeta; 3594 } 3595 3596 /** Check an annotation value. 3597 * 3598 * @param a The annotation tree to check 3599 * @return true if this annotation tree is valid, otherwise false 3600 */ 3601 public boolean validateAnnotationDeferErrors(JCAnnotation a) { 3602 boolean res = false; 3603 final Log.DiagnosticHandler diagHandler = log.new DiscardDiagnosticHandler(); 3604 try { 3605 res = validateAnnotation(a); 3606 } finally { 3607 log.popDiagnosticHandler(diagHandler); 3608 } 3609 return res; 3610 } 3611 3612 private boolean validateAnnotation(JCAnnotation a) { 3613 boolean isValid = true; 3614 AnnotationTypeMetadata metadata = a.annotationType.type.tsym.getAnnotationTypeMetadata(); 3615 3616 // collect an inventory of the annotation elements 3617 Set<MethodSymbol> elements = metadata.getAnnotationElements(); 3618 3619 // remove the ones that are assigned values 3620 for (JCTree arg : a.args) { 3621 if (!arg.hasTag(ASSIGN)) continue; // recovery 3622 JCAssign assign = (JCAssign)arg; 3623 Symbol m = TreeInfo.symbol(assign.lhs); 3624 if (m == null || m.type.isErroneous()) continue; 3625 if (!elements.remove(m)) { 3626 isValid = false; 3627 log.error(assign.lhs.pos(), 3628 Errors.DuplicateAnnotationMemberValue(m.name, a.type)); 3629 } 3630 } 3631 3632 // all the remaining ones better have default values 3633 List<Name> missingDefaults = List.nil(); 3634 Set<MethodSymbol> membersWithDefault = metadata.getAnnotationElementsWithDefault(); 3635 for (MethodSymbol m : elements) { 3636 if (m.type.isErroneous()) 3637 continue; 3638 3639 if (!membersWithDefault.contains(m)) 3640 missingDefaults = missingDefaults.append(m.name); 3641 } 3642 missingDefaults = missingDefaults.reverse(); 3643 if (missingDefaults.nonEmpty()) { 3644 isValid = false; 3645 Error errorKey = (missingDefaults.size() > 1) 3646 ? Errors.AnnotationMissingDefaultValue1(a.type, missingDefaults) 3647 : Errors.AnnotationMissingDefaultValue(a.type, missingDefaults); 3648 log.error(a.pos(), errorKey); 3649 } 3650 3651 return isValid && validateTargetAnnotationValue(a); 3652 } 3653 3654 /* Validate the special java.lang.annotation.Target annotation */ 3655 boolean validateTargetAnnotationValue(JCAnnotation a) { 3656 // special case: java.lang.annotation.Target must not have 3657 // repeated values in its value member 3658 if (a.annotationType.type.tsym != syms.annotationTargetType.tsym || 3659 a.args.tail == null) 3660 return true; 3661 3662 boolean isValid = true; 3663 if (!a.args.head.hasTag(ASSIGN)) return false; // error recovery 3664 JCAssign assign = (JCAssign) a.args.head; 3665 Symbol m = TreeInfo.symbol(assign.lhs); 3666 if (m.name != names.value) return false; 3667 JCTree rhs = assign.rhs; 3668 if (!rhs.hasTag(NEWARRAY)) return false; 3669 JCNewArray na = (JCNewArray) rhs; 3670 Set<Symbol> targets = new HashSet<>(); 3671 for (JCTree elem : na.elems) { 3672 if (!targets.add(TreeInfo.symbol(elem))) { 3673 isValid = false; 3674 log.error(elem.pos(), Errors.RepeatedAnnotationTarget); 3675 } 3676 } 3677 return isValid; 3678 } 3679 3680 void checkDeprecatedAnnotation(DiagnosticPosition pos, Symbol s) { 3681 if (lint.isEnabled(LintCategory.DEP_ANN) && s.isDeprecatableViaAnnotation() && 3682 (s.flags() & DEPRECATED) != 0 && 3683 !syms.deprecatedType.isErroneous() && 3684 s.attribute(syms.deprecatedType.tsym) == null) { 3685 log.warning(pos, LintWarnings.MissingDeprecatedAnnotation); 3686 } 3687 // Note: @Deprecated has no effect on local variables, parameters and package decls. 3688 if (lint.isEnabled(LintCategory.DEPRECATION) && !s.isDeprecatableViaAnnotation()) { 3689 if (!syms.deprecatedType.isErroneous() && s.attribute(syms.deprecatedType.tsym) != null) { 3690 log.warning(pos, LintWarnings.DeprecatedAnnotationHasNoEffect(Kinds.kindName(s))); 3691 } 3692 } 3693 } 3694 3695 void checkDeprecated(final DiagnosticPosition pos, final Symbol other, final Symbol s) { 3696 checkDeprecated(() -> pos, other, s); 3697 } 3698 3699 void checkDeprecated(Supplier<DiagnosticPosition> pos, final Symbol other, final Symbol s) { 3700 if (!importSuppression 3701 && (s.isDeprecatedForRemoval() || s.isDeprecated() && !other.isDeprecated()) 3702 && (s.outermostClass() != other.outermostClass() || s.outermostClass() == null) 3703 && s.kind != Kind.PCK) { 3704 warnDeprecated(pos.get(), s); 3705 } 3706 } 3707 3708 void checkSunAPI(final DiagnosticPosition pos, final Symbol s) { 3709 if ((s.flags() & PROPRIETARY) != 0) { 3710 log.warning(pos, Warnings.SunProprietary(s)); 3711 } 3712 } 3713 3714 void checkProfile(final DiagnosticPosition pos, final Symbol s) { 3715 if (profile != Profile.DEFAULT && (s.flags() & NOT_IN_PROFILE) != 0) { 3716 log.error(pos, Errors.NotInProfile(s, profile)); 3717 } 3718 } 3719 3720 void checkPreview(DiagnosticPosition pos, Symbol other, Symbol s) { 3721 checkPreview(pos, other, Type.noType, s); 3722 } 3723 3724 void checkPreview(DiagnosticPosition pos, Symbol other, Type site, Symbol s) { 3725 boolean sIsPreview; 3726 Symbol previewSymbol; 3727 if ((s.flags() & PREVIEW_API) != 0) { 3728 sIsPreview = true; 3729 previewSymbol= s; 3730 } else if ((s.kind == Kind.MTH || s.kind == Kind.VAR) && 3731 site.tsym != null && 3732 (site.tsym.flags() & PREVIEW_API) == 0 && 3733 (s.owner.flags() & PREVIEW_API) != 0) { 3734 //calling a method, or using a field, whose owner is a preview, but 3735 //using a site that is not a preview. Also produce an error or warning: 3736 sIsPreview = true; 3737 previewSymbol = s.owner; 3738 } else { 3739 sIsPreview = false; 3740 previewSymbol = null; 3741 } 3742 if (sIsPreview && !preview.participatesInPreview(syms, other, s) && !disablePreviewCheck) { 3743 if ((previewSymbol.flags() & PREVIEW_REFLECTIVE) == 0) { 3744 if (!preview.isEnabled()) { 3745 log.error(pos, Errors.IsPreview(s)); 3746 } else { 3747 preview.markUsesPreview(pos); 3748 warnPreviewAPI(pos, LintWarnings.IsPreview(s)); 3749 } 3750 } else { 3751 warnPreviewAPI(pos, LintWarnings.IsPreviewReflective(s)); 3752 } 3753 } 3754 if (preview.declaredUsingPreviewFeature(s)) { 3755 if (preview.isEnabled()) { 3756 //for preview disabled do presumably so not need to do anything? 3757 //If "s" is compiled from source, then there was an error for it already; 3758 //if "s" is from classfile, there already was an error for the classfile. 3759 preview.markUsesPreview(pos); 3760 warnPreviewAPI(pos, LintWarnings.DeclaredUsingPreview(kindName(s), s)); 3761 } 3762 } 3763 } 3764 3765 void checkRestricted(DiagnosticPosition pos, Symbol s) { 3766 if (s.kind == MTH && (s.flags() & RESTRICTED) != 0) { 3767 log.warning(pos, LintWarnings.RestrictedMethod(s.enclClass(), s)); 3768 } 3769 } 3770 3771 /* ************************************************************************* 3772 * Check for recursive annotation elements. 3773 **************************************************************************/ 3774 3775 /** Check for cycles in the graph of annotation elements. 3776 */ 3777 void checkNonCyclicElements(JCClassDecl tree) { 3778 if ((tree.sym.flags_field & ANNOTATION) == 0) return; 3779 Assert.check((tree.sym.flags_field & LOCKED) == 0); 3780 try { 3781 tree.sym.flags_field |= LOCKED; 3782 for (JCTree def : tree.defs) { 3783 if (!def.hasTag(METHODDEF)) continue; 3784 JCMethodDecl meth = (JCMethodDecl)def; 3785 checkAnnotationResType(meth.pos(), meth.restype.type); 3786 } 3787 } finally { 3788 tree.sym.flags_field &= ~LOCKED; 3789 tree.sym.flags_field |= ACYCLIC_ANN; 3790 } 3791 } 3792 3793 void checkNonCyclicElementsInternal(DiagnosticPosition pos, TypeSymbol tsym) { 3794 if ((tsym.flags_field & ACYCLIC_ANN) != 0) 3795 return; 3796 if ((tsym.flags_field & LOCKED) != 0) { 3797 log.error(pos, Errors.CyclicAnnotationElement(tsym)); 3798 return; 3799 } 3800 try { 3801 tsym.flags_field |= LOCKED; 3802 for (Symbol s : tsym.members().getSymbols(NON_RECURSIVE)) { 3803 if (s.kind != MTH) 3804 continue; 3805 checkAnnotationResType(pos, ((MethodSymbol)s).type.getReturnType()); 3806 } 3807 } finally { 3808 tsym.flags_field &= ~LOCKED; 3809 tsym.flags_field |= ACYCLIC_ANN; 3810 } 3811 } 3812 3813 void checkAnnotationResType(DiagnosticPosition pos, Type type) { 3814 switch (type.getTag()) { 3815 case CLASS: 3816 if ((type.tsym.flags() & ANNOTATION) != 0) 3817 checkNonCyclicElementsInternal(pos, type.tsym); 3818 break; 3819 case ARRAY: 3820 checkAnnotationResType(pos, types.elemtype(type)); 3821 break; 3822 default: 3823 break; // int etc 3824 } 3825 } 3826 3827 /* ************************************************************************* 3828 * Check for cycles in the constructor call graph. 3829 **************************************************************************/ 3830 3831 /** Check for cycles in the graph of constructors calling other 3832 * constructors. 3833 */ 3834 void checkCyclicConstructors(JCClassDecl tree) { 3835 // use LinkedHashMap so we generate errors deterministically 3836 Map<Symbol,Symbol> callMap = new LinkedHashMap<>(); 3837 3838 // enter each constructor this-call into the map 3839 for (List<JCTree> l = tree.defs; l.nonEmpty(); l = l.tail) { 3840 if (!TreeInfo.isConstructor(l.head)) 3841 continue; 3842 JCMethodDecl meth = (JCMethodDecl)l.head; 3843 JCMethodInvocation app = TreeInfo.findConstructorCall(meth); 3844 if (app != null && TreeInfo.name(app.meth) == names._this) { 3845 callMap.put(meth.sym, TreeInfo.symbol(app.meth)); 3846 } else { 3847 meth.sym.flags_field |= ACYCLIC; 3848 } 3849 } 3850 3851 // Check for cycles in the map 3852 Symbol[] ctors = new Symbol[0]; 3853 ctors = callMap.keySet().toArray(ctors); 3854 for (Symbol caller : ctors) { 3855 checkCyclicConstructor(tree, caller, callMap); 3856 } 3857 } 3858 3859 /** Look in the map to see if the given constructor is part of a 3860 * call cycle. 3861 */ 3862 private void checkCyclicConstructor(JCClassDecl tree, Symbol ctor, 3863 Map<Symbol,Symbol> callMap) { 3864 if (ctor != null && (ctor.flags_field & ACYCLIC) == 0) { 3865 if ((ctor.flags_field & LOCKED) != 0) { 3866 log.error(TreeInfo.diagnosticPositionFor(ctor, tree, false, t -> t.hasTag(IDENT)), 3867 Errors.RecursiveCtorInvocation); 3868 } else { 3869 ctor.flags_field |= LOCKED; 3870 checkCyclicConstructor(tree, callMap.remove(ctor), callMap); 3871 ctor.flags_field &= ~LOCKED; 3872 } 3873 ctor.flags_field |= ACYCLIC; 3874 } 3875 } 3876 3877 /* ************************************************************************* 3878 * Verify the proper placement of super()/this() calls. 3879 * 3880 * - super()/this() may only appear in constructors 3881 * - There must be at most one super()/this() call per constructor 3882 * - The super()/this() call, if any, must be a top-level statement in the 3883 * constructor, i.e., not nested inside any other statement or block 3884 * - There must be no return statements prior to the super()/this() call 3885 **************************************************************************/ 3886 3887 void checkSuperInitCalls(JCClassDecl tree) { 3888 new SuperThisChecker().check(tree); 3889 } 3890 3891 private class SuperThisChecker extends TreeScanner { 3892 3893 // Match this scan stack: 1=JCMethodDecl, 2=JCExpressionStatement, 3=JCMethodInvocation 3894 private static final int MATCH_SCAN_DEPTH = 3; 3895 3896 private boolean constructor; // is this method a constructor? 3897 private boolean firstStatement; // at the first statement in method? 3898 private JCReturn earlyReturn; // first return prior to the super()/init(), if any 3899 private Name initCall; // whichever of "super" or "init" we've seen already 3900 private int scanDepth; // current scan recursion depth in method body 3901 3902 public void check(JCClassDecl classDef) { 3903 scan(classDef.defs); 3904 } 3905 3906 @Override 3907 public void visitMethodDef(JCMethodDecl tree) { 3908 Assert.check(!constructor); 3909 Assert.check(earlyReturn == null); 3910 Assert.check(initCall == null); 3911 Assert.check(scanDepth == 1); 3912 3913 // Initialize state for this method 3914 constructor = TreeInfo.isConstructor(tree); 3915 try { 3916 3917 // Scan method body 3918 if (tree.body != null) { 3919 firstStatement = true; 3920 for (List<JCStatement> l = tree.body.stats; l.nonEmpty(); l = l.tail) { 3921 scan(l.head); 3922 firstStatement = false; 3923 } 3924 } 3925 3926 // Verify no 'return' seen prior to an explicit super()/this() call 3927 if (constructor && earlyReturn != null && initCall != null) 3928 log.error(earlyReturn.pos(), Errors.ReturnBeforeSuperclassInitialized); 3929 } finally { 3930 firstStatement = false; 3931 constructor = false; 3932 earlyReturn = null; 3933 initCall = null; 3934 } 3935 } 3936 3937 @Override 3938 public void scan(JCTree tree) { 3939 scanDepth++; 3940 try { 3941 super.scan(tree); 3942 } finally { 3943 scanDepth--; 3944 } 3945 } 3946 3947 @Override 3948 public void visitApply(JCMethodInvocation apply) { 3949 do { 3950 3951 // Is this a super() or this() call? 3952 Name methodName = TreeInfo.name(apply.meth); 3953 if (methodName != names._super && methodName != names._this) 3954 break; 3955 3956 // super()/this() calls must only appear in a constructor 3957 if (!constructor) { 3958 log.error(apply.pos(), Errors.CallMustOnlyAppearInCtor); 3959 break; 3960 } 3961 3962 // super()/this() calls must be a top level statement 3963 if (scanDepth != MATCH_SCAN_DEPTH) { 3964 log.error(apply.pos(), Errors.CtorCallsNotAllowedHere); 3965 break; 3966 } 3967 3968 // super()/this() calls must not appear more than once 3969 if (initCall != null) { 3970 log.error(apply.pos(), Errors.RedundantSuperclassInit); 3971 break; 3972 } 3973 3974 // If super()/this() isn't first, require flexible constructors feature 3975 if (!firstStatement) 3976 preview.checkSourceLevel(apply.pos(), Feature.FLEXIBLE_CONSTRUCTORS); 3977 3978 // We found a legitimate super()/this() call; remember it 3979 initCall = methodName; 3980 } while (false); 3981 3982 // Proceed 3983 super.visitApply(apply); 3984 } 3985 3986 @Override 3987 public void visitReturn(JCReturn tree) { 3988 if (constructor && initCall == null && earlyReturn == null) 3989 earlyReturn = tree; // we have seen a return but not (yet) a super()/this() 3990 super.visitReturn(tree); 3991 } 3992 3993 @Override 3994 public void visitClassDef(JCClassDecl tree) { 3995 // don't descend any further 3996 } 3997 3998 @Override 3999 public void visitLambda(JCLambda tree) { 4000 final boolean constructorPrev = constructor; 4001 final boolean firstStatementPrev = firstStatement; 4002 final JCReturn earlyReturnPrev = earlyReturn; 4003 final Name initCallPrev = initCall; 4004 final int scanDepthPrev = scanDepth; 4005 constructor = false; 4006 firstStatement = false; 4007 earlyReturn = null; 4008 initCall = null; 4009 scanDepth = 0; 4010 try { 4011 super.visitLambda(tree); 4012 } finally { 4013 constructor = constructorPrev; 4014 firstStatement = firstStatementPrev; 4015 earlyReturn = earlyReturnPrev; 4016 initCall = initCallPrev; 4017 scanDepth = scanDepthPrev; 4018 } 4019 } 4020 } 4021 4022 /* ************************************************************************* 4023 * Miscellaneous 4024 **************************************************************************/ 4025 4026 /** 4027 * Check for division by integer constant zero 4028 * @param pos Position for error reporting. 4029 * @param operator The operator for the expression 4030 * @param operand The right hand operand for the expression 4031 */ 4032 void checkDivZero(final DiagnosticPosition pos, Symbol operator, Type operand) { 4033 if (operand.constValue() != null 4034 && operand.getTag().isSubRangeOf(LONG) 4035 && ((Number) (operand.constValue())).longValue() == 0) { 4036 int opc = ((OperatorSymbol)operator).opcode; 4037 if (opc == ByteCodes.idiv || opc == ByteCodes.imod 4038 || opc == ByteCodes.ldiv || opc == ByteCodes.lmod) { 4039 log.warning(pos, LintWarnings.DivZero); 4040 } 4041 } 4042 } 4043 4044 /** 4045 * Check for possible loss of precission 4046 * @param pos Position for error reporting. 4047 * @param found The computed type of the tree 4048 * @param req The computed type of the tree 4049 */ 4050 void checkLossOfPrecision(final DiagnosticPosition pos, Type found, Type req) { 4051 if (found.isNumeric() && req.isNumeric() && !types.isAssignable(found, req)) { 4052 log.warning(pos, LintWarnings.PossibleLossOfPrecision(found, req)); 4053 } 4054 } 4055 4056 /** 4057 * Check for empty statements after if 4058 */ 4059 void checkEmptyIf(JCIf tree) { 4060 if (tree.thenpart.hasTag(SKIP) && tree.elsepart == null) { 4061 log.warning(tree.thenpart.pos(), LintWarnings.EmptyIf); 4062 } 4063 } 4064 4065 /** Check that symbol is unique in given scope. 4066 * @param pos Position for error reporting. 4067 * @param sym The symbol. 4068 * @param s The scope. 4069 */ 4070 boolean checkUnique(DiagnosticPosition pos, Symbol sym, Scope s) { 4071 if (sym.type.isErroneous()) 4072 return true; 4073 if (sym.owner.name == names.any) return false; 4074 for (Symbol byName : s.getSymbolsByName(sym.name, NON_RECURSIVE)) { 4075 if (sym != byName && 4076 (byName.flags() & CLASH) == 0 && 4077 sym.kind == byName.kind && 4078 sym.name != names.error && 4079 (sym.kind != MTH || 4080 types.hasSameArgs(sym.type, byName.type) || 4081 types.hasSameArgs(types.erasure(sym.type), types.erasure(byName.type)))) { 4082 if ((sym.flags() & VARARGS) != (byName.flags() & VARARGS)) { 4083 sym.flags_field |= CLASH; 4084 varargsDuplicateError(pos, sym, byName); 4085 return true; 4086 } else if (sym.kind == MTH && !types.hasSameArgs(sym.type, byName.type, false)) { 4087 duplicateErasureError(pos, sym, byName); 4088 sym.flags_field |= CLASH; 4089 return true; 4090 } else if ((sym.flags() & MATCH_BINDING) != 0 && 4091 (byName.flags() & MATCH_BINDING) != 0 && 4092 (byName.flags() & MATCH_BINDING_TO_OUTER) == 0) { 4093 if (!sym.type.isErroneous()) { 4094 log.error(pos, Errors.MatchBindingExists); 4095 sym.flags_field |= CLASH; 4096 } 4097 return false; 4098 } else { 4099 duplicateError(pos, byName); 4100 return false; 4101 } 4102 } 4103 } 4104 return true; 4105 } 4106 4107 /** Report duplicate declaration error. 4108 */ 4109 void duplicateErasureError(DiagnosticPosition pos, Symbol sym1, Symbol sym2) { 4110 if (!sym1.type.isErroneous() && !sym2.type.isErroneous()) { 4111 log.error(pos, Errors.NameClashSameErasure(sym1, sym2)); 4112 } 4113 } 4114 4115 /**Check that types imported through the ordinary imports don't clash with types imported 4116 * by other (static or ordinary) imports. Note that two static imports may import two clashing 4117 * types without an error on the imports. 4118 * @param toplevel The toplevel tree for which the test should be performed. 4119 */ 4120 void checkImportsUnique(JCCompilationUnit toplevel) { 4121 WriteableScope ordinallyImportedSoFar = WriteableScope.create(toplevel.packge); 4122 WriteableScope staticallyImportedSoFar = WriteableScope.create(toplevel.packge); 4123 WriteableScope topLevelScope = toplevel.toplevelScope; 4124 4125 for (JCTree def : toplevel.defs) { 4126 if (!def.hasTag(IMPORT)) 4127 continue; 4128 4129 JCImport imp = (JCImport) def; 4130 4131 if (imp.importScope == null) 4132 continue; 4133 4134 for (Symbol sym : imp.importScope.getSymbols(sym -> sym.kind == TYP)) { 4135 if (imp.isStatic()) { 4136 checkUniqueImport(imp.pos(), ordinallyImportedSoFar, staticallyImportedSoFar, topLevelScope, sym, true); 4137 staticallyImportedSoFar.enter(sym); 4138 } else { 4139 checkUniqueImport(imp.pos(), ordinallyImportedSoFar, staticallyImportedSoFar, topLevelScope, sym, false); 4140 ordinallyImportedSoFar.enter(sym); 4141 } 4142 } 4143 4144 imp.importScope = null; 4145 } 4146 } 4147 4148 /** Check that single-type import is not already imported or top-level defined, 4149 * but make an exception for two single-type imports which denote the same type. 4150 * @param pos Position for error reporting. 4151 * @param ordinallyImportedSoFar A Scope containing types imported so far through 4152 * ordinary imports. 4153 * @param staticallyImportedSoFar A Scope containing types imported so far through 4154 * static imports. 4155 * @param topLevelScope The current file's top-level Scope 4156 * @param sym The symbol. 4157 * @param staticImport Whether or not this was a static import 4158 */ 4159 private boolean checkUniqueImport(DiagnosticPosition pos, Scope ordinallyImportedSoFar, 4160 Scope staticallyImportedSoFar, Scope topLevelScope, 4161 Symbol sym, boolean staticImport) { 4162 Predicate<Symbol> duplicates = candidate -> candidate != sym && !candidate.type.isErroneous(); 4163 Symbol ordinaryClashing = ordinallyImportedSoFar.findFirst(sym.name, duplicates); 4164 Symbol staticClashing = null; 4165 if (ordinaryClashing == null && !staticImport) { 4166 staticClashing = staticallyImportedSoFar.findFirst(sym.name, duplicates); 4167 } 4168 if (ordinaryClashing != null || staticClashing != null) { 4169 if (ordinaryClashing != null) 4170 log.error(pos, Errors.AlreadyDefinedSingleImport(ordinaryClashing)); 4171 else 4172 log.error(pos, Errors.AlreadyDefinedStaticSingleImport(staticClashing)); 4173 return false; 4174 } 4175 Symbol clashing = topLevelScope.findFirst(sym.name, duplicates); 4176 if (clashing != null) { 4177 log.error(pos, Errors.AlreadyDefinedThisUnit(clashing)); 4178 return false; 4179 } 4180 return true; 4181 } 4182 4183 /** Check that a qualified name is in canonical form (for import decls). 4184 */ 4185 public void checkCanonical(JCTree tree) { 4186 if (!isCanonical(tree)) 4187 log.error(tree.pos(), 4188 Errors.ImportRequiresCanonical(TreeInfo.symbol(tree))); 4189 } 4190 // where 4191 private boolean isCanonical(JCTree tree) { 4192 while (tree.hasTag(SELECT)) { 4193 JCFieldAccess s = (JCFieldAccess) tree; 4194 if (s.sym.owner.getQualifiedName() != TreeInfo.symbol(s.selected).getQualifiedName()) 4195 return false; 4196 tree = s.selected; 4197 } 4198 return true; 4199 } 4200 4201 /** Check that an auxiliary class is not accessed from any other file than its own. 4202 */ 4203 void checkForBadAuxiliaryClassAccess(DiagnosticPosition pos, Env<AttrContext> env, ClassSymbol c) { 4204 if ((c.flags() & AUXILIARY) != 0 && 4205 rs.isAccessible(env, c) && 4206 !fileManager.isSameFile(c.sourcefile, env.toplevel.sourcefile)) 4207 { 4208 log.warning(pos, LintWarnings.AuxiliaryClassAccessedFromOutsideOfItsSourceFile(c, c.sourcefile)); 4209 } 4210 } 4211 4212 /** 4213 * Check for a default constructor in an exported package. 4214 */ 4215 void checkDefaultConstructor(ClassSymbol c, DiagnosticPosition pos) { 4216 if (lint.isEnabled(LintCategory.MISSING_EXPLICIT_CTOR) && 4217 ((c.flags() & (ENUM | RECORD)) == 0) && 4218 !c.isAnonymous() && 4219 ((c.flags() & (PUBLIC | PROTECTED)) != 0) && 4220 Feature.MODULES.allowedInSource(source)) { 4221 NestingKind nestingKind = c.getNestingKind(); 4222 switch (nestingKind) { 4223 case ANONYMOUS, 4224 LOCAL -> {return;} 4225 case TOP_LEVEL -> {;} // No additional checks needed 4226 case MEMBER -> { 4227 // For nested member classes, all the enclosing 4228 // classes must be public or protected. 4229 Symbol owner = c.owner; 4230 while (owner != null && owner.kind == TYP) { 4231 if ((owner.flags() & (PUBLIC | PROTECTED)) == 0) 4232 return; 4233 owner = owner.owner; 4234 } 4235 } 4236 } 4237 4238 // Only check classes in named packages exported by its module 4239 PackageSymbol pkg = c.packge(); 4240 if (!pkg.isUnnamed()) { 4241 ModuleSymbol modle = pkg.modle; 4242 for (ExportsDirective exportDir : modle.exports) { 4243 // Report warning only if the containing 4244 // package is unconditionally exported 4245 if (exportDir.packge.equals(pkg)) { 4246 if (exportDir.modules == null || exportDir.modules.isEmpty()) { 4247 // Warning may be suppressed by 4248 // annotations; check again for being 4249 // enabled in the deferred context. 4250 log.warning(pos, LintWarnings.MissingExplicitCtor(c, pkg, modle)); 4251 } else { 4252 return; 4253 } 4254 } 4255 } 4256 } 4257 } 4258 return; 4259 } 4260 4261 private class ConversionWarner extends Warner { 4262 final String uncheckedKey; 4263 final Type found; 4264 final Type expected; 4265 public ConversionWarner(DiagnosticPosition pos, String uncheckedKey, Type found, Type expected) { 4266 super(pos); 4267 this.uncheckedKey = uncheckedKey; 4268 this.found = found; 4269 this.expected = expected; 4270 } 4271 4272 @Override 4273 public void warn(LintCategory lint) { 4274 boolean warned = this.warned; 4275 super.warn(lint); 4276 if (warned) return; // suppress redundant diagnostics 4277 switch (lint) { 4278 case UNCHECKED: 4279 Check.this.warnUnchecked(pos(), LintWarnings.ProbFoundReq(diags.fragment(uncheckedKey), found, expected)); 4280 break; 4281 case VARARGS: 4282 if (method != null && 4283 method.attribute(syms.trustMeType.tsym) != null && 4284 isTrustMeAllowedOnMethod(method) && 4285 !types.isReifiable(method.type.getParameterTypes().last())) { 4286 log.warning(pos(), LintWarnings.VarargsUnsafeUseVarargsParam(method.params.last())); 4287 } 4288 break; 4289 default: 4290 throw new AssertionError("Unexpected lint: " + lint); 4291 } 4292 } 4293 } 4294 4295 public Warner castWarner(DiagnosticPosition pos, Type found, Type expected) { 4296 return new ConversionWarner(pos, "unchecked.cast.to.type", found, expected); 4297 } 4298 4299 public Warner convertWarner(DiagnosticPosition pos, Type found, Type expected) { 4300 return new ConversionWarner(pos, "unchecked.assign", found, expected); 4301 } 4302 4303 public void checkFunctionalInterface(JCClassDecl tree, ClassSymbol cs) { 4304 Compound functionalType = cs.attribute(syms.functionalInterfaceType.tsym); 4305 4306 if (functionalType != null) { 4307 try { 4308 types.findDescriptorSymbol((TypeSymbol)cs); 4309 } catch (Types.FunctionDescriptorLookupError ex) { 4310 DiagnosticPosition pos = tree.pos(); 4311 for (JCAnnotation a : tree.getModifiers().annotations) { 4312 if (a.annotationType.type.tsym == syms.functionalInterfaceType.tsym) { 4313 pos = a.pos(); 4314 break; 4315 } 4316 } 4317 log.error(pos, Errors.BadFunctionalIntfAnno1(ex.getDiagnostic())); 4318 } 4319 } 4320 } 4321 4322 public void checkImportsResolvable(final JCCompilationUnit toplevel) { 4323 for (final JCImportBase impBase : toplevel.getImports()) { 4324 if (!(impBase instanceof JCImport imp)) 4325 continue; 4326 if (!imp.staticImport || !imp.qualid.hasTag(SELECT)) 4327 continue; 4328 final JCFieldAccess select = imp.qualid; 4329 final Symbol origin; 4330 if (select.name == names.asterisk || (origin = TreeInfo.symbol(select.selected)) == null || origin.kind != TYP) 4331 continue; 4332 4333 TypeSymbol site = (TypeSymbol) TreeInfo.symbol(select.selected); 4334 if (!checkTypeContainsImportableElement(site, site, toplevel.packge, select.name, new HashSet<Symbol>())) { 4335 log.error(imp.pos(), 4336 Errors.CantResolveLocation(KindName.STATIC, 4337 select.name, 4338 null, 4339 null, 4340 Fragments.Location(kindName(site), 4341 site, 4342 null))); 4343 } 4344 } 4345 } 4346 4347 // Check that packages imported are in scope (JLS 7.4.3, 6.3, 6.5.3.1, 6.5.3.2) 4348 public void checkImportedPackagesObservable(final JCCompilationUnit toplevel) { 4349 OUTER: for (JCImportBase impBase : toplevel.getImports()) { 4350 if (impBase instanceof JCImport imp && !imp.staticImport && 4351 TreeInfo.name(imp.qualid) == names.asterisk) { 4352 TypeSymbol tsym = imp.qualid.selected.type.tsym; 4353 if (tsym.kind == PCK && tsym.members().isEmpty() && 4354 !(Feature.IMPORT_ON_DEMAND_OBSERVABLE_PACKAGES.allowedInSource(source) && tsym.exists())) { 4355 log.error(DiagnosticFlag.RESOLVE_ERROR, imp.qualid.selected.pos(), Errors.DoesntExist(tsym)); 4356 } 4357 } 4358 } 4359 } 4360 4361 private boolean checkTypeContainsImportableElement(TypeSymbol tsym, TypeSymbol origin, PackageSymbol packge, Name name, Set<Symbol> processed) { 4362 if (tsym == null || !processed.add(tsym)) 4363 return false; 4364 4365 // also search through inherited names 4366 if (checkTypeContainsImportableElement(types.supertype(tsym.type).tsym, origin, packge, name, processed)) 4367 return true; 4368 4369 for (Type t : types.interfaces(tsym.type)) 4370 if (checkTypeContainsImportableElement(t.tsym, origin, packge, name, processed)) 4371 return true; 4372 4373 for (Symbol sym : tsym.members().getSymbolsByName(name)) { 4374 if (sym.isStatic() && 4375 importAccessible(sym, packge) && 4376 sym.isMemberOf(origin, types)) { 4377 return true; 4378 } 4379 } 4380 4381 return false; 4382 } 4383 4384 // is the sym accessible everywhere in packge? 4385 public boolean importAccessible(Symbol sym, PackageSymbol packge) { 4386 try { 4387 int flags = (int)(sym.flags() & AccessFlags); 4388 switch (flags) { 4389 default: 4390 case PUBLIC: 4391 return true; 4392 case PRIVATE: 4393 return false; 4394 case 0: 4395 case PROTECTED: 4396 return sym.packge() == packge; 4397 } 4398 } catch (ClassFinder.BadClassFile err) { 4399 throw err; 4400 } catch (CompletionFailure ex) { 4401 return false; 4402 } 4403 } 4404 4405 public void checkLeaksNotAccessible(Env<AttrContext> env, JCClassDecl check) { 4406 JCCompilationUnit toplevel = env.toplevel; 4407 4408 if ( toplevel.modle == syms.unnamedModule 4409 || toplevel.modle == syms.noModule 4410 || (check.sym.flags() & COMPOUND) != 0) { 4411 return ; 4412 } 4413 4414 ExportsDirective currentExport = findExport(toplevel.packge); 4415 4416 if ( currentExport == null //not exported 4417 || currentExport.modules != null) //don't check classes in qualified export 4418 return ; 4419 4420 new TreeScanner() { 4421 Lint lint = env.info.lint; 4422 boolean inSuperType; 4423 4424 @Override 4425 public void visitBlock(JCBlock tree) { 4426 } 4427 @Override 4428 public void visitMethodDef(JCMethodDecl tree) { 4429 if (!isAPISymbol(tree.sym)) 4430 return; 4431 Lint prevLint = lint; 4432 try { 4433 lint = lint.augment(tree.sym); 4434 if (lint.isEnabled(LintCategory.EXPORTS)) { 4435 super.visitMethodDef(tree); 4436 } 4437 } finally { 4438 lint = prevLint; 4439 } 4440 } 4441 @Override 4442 public void visitVarDef(JCVariableDecl tree) { 4443 if (!isAPISymbol(tree.sym) && tree.sym.owner.kind != MTH) 4444 return; 4445 Lint prevLint = lint; 4446 try { 4447 lint = lint.augment(tree.sym); 4448 if (lint.isEnabled(LintCategory.EXPORTS)) { 4449 scan(tree.mods); 4450 scan(tree.vartype); 4451 } 4452 } finally { 4453 lint = prevLint; 4454 } 4455 } 4456 @Override 4457 public void visitClassDef(JCClassDecl tree) { 4458 if (tree != check) 4459 return ; 4460 4461 if (!isAPISymbol(tree.sym)) 4462 return ; 4463 4464 Lint prevLint = lint; 4465 try { 4466 lint = lint.augment(tree.sym); 4467 if (lint.isEnabled(LintCategory.EXPORTS)) { 4468 scan(tree.mods); 4469 scan(tree.typarams); 4470 try { 4471 inSuperType = true; 4472 scan(tree.extending); 4473 scan(tree.implementing); 4474 } finally { 4475 inSuperType = false; 4476 } 4477 scan(tree.defs); 4478 } 4479 } finally { 4480 lint = prevLint; 4481 } 4482 } 4483 @Override 4484 public void visitTypeApply(JCTypeApply tree) { 4485 scan(tree.clazz); 4486 boolean oldInSuperType = inSuperType; 4487 try { 4488 inSuperType = false; 4489 scan(tree.arguments); 4490 } finally { 4491 inSuperType = oldInSuperType; 4492 } 4493 } 4494 @Override 4495 public void visitIdent(JCIdent tree) { 4496 Symbol sym = TreeInfo.symbol(tree); 4497 if (sym.kind == TYP && !sym.type.hasTag(TYPEVAR)) { 4498 checkVisible(tree.pos(), sym, toplevel.packge, inSuperType); 4499 } 4500 } 4501 4502 @Override 4503 public void visitSelect(JCFieldAccess tree) { 4504 Symbol sym = TreeInfo.symbol(tree); 4505 Symbol sitesym = TreeInfo.symbol(tree.selected); 4506 if (sym.kind == TYP && sitesym.kind == PCK) { 4507 checkVisible(tree.pos(), sym, toplevel.packge, inSuperType); 4508 } else { 4509 super.visitSelect(tree); 4510 } 4511 } 4512 4513 @Override 4514 public void visitAnnotation(JCAnnotation tree) { 4515 if (tree.attribute.type.tsym.getAnnotation(java.lang.annotation.Documented.class) != null) 4516 super.visitAnnotation(tree); 4517 } 4518 4519 }.scan(check); 4520 } 4521 //where: 4522 private ExportsDirective findExport(PackageSymbol pack) { 4523 for (ExportsDirective d : pack.modle.exports) { 4524 if (d.packge == pack) 4525 return d; 4526 } 4527 4528 return null; 4529 } 4530 private boolean isAPISymbol(Symbol sym) { 4531 while (sym.kind != PCK) { 4532 if ((sym.flags() & Flags.PUBLIC) == 0 && (sym.flags() & Flags.PROTECTED) == 0) { 4533 return false; 4534 } 4535 sym = sym.owner; 4536 } 4537 return true; 4538 } 4539 private void checkVisible(DiagnosticPosition pos, Symbol what, PackageSymbol inPackage, boolean inSuperType) { 4540 if (!isAPISymbol(what) && !inSuperType) { //package private/private element 4541 log.warning(pos, LintWarnings.LeaksNotAccessible(kindName(what), what, what.packge().modle)); 4542 return ; 4543 } 4544 4545 PackageSymbol whatPackage = what.packge(); 4546 ExportsDirective whatExport = findExport(whatPackage); 4547 ExportsDirective inExport = findExport(inPackage); 4548 4549 if (whatExport == null) { //package not exported: 4550 log.warning(pos, LintWarnings.LeaksNotAccessibleUnexported(kindName(what), what, what.packge().modle)); 4551 return ; 4552 } 4553 4554 if (whatExport.modules != null) { 4555 if (inExport.modules == null || !whatExport.modules.containsAll(inExport.modules)) { 4556 log.warning(pos, LintWarnings.LeaksNotAccessibleUnexportedQualified(kindName(what), what, what.packge().modle)); 4557 } 4558 } 4559 4560 if (whatPackage.modle != inPackage.modle && whatPackage.modle != syms.java_base) { 4561 //check that relativeTo.modle requires transitive what.modle, somehow: 4562 List<ModuleSymbol> todo = List.of(inPackage.modle); 4563 4564 while (todo.nonEmpty()) { 4565 ModuleSymbol current = todo.head; 4566 todo = todo.tail; 4567 if (current == whatPackage.modle) 4568 return ; //OK 4569 if ((current.flags() & Flags.AUTOMATIC_MODULE) != 0) 4570 continue; //for automatic modules, don't look into their dependencies 4571 for (RequiresDirective req : current.requires) { 4572 if (req.isTransitive()) { 4573 todo = todo.prepend(req.module); 4574 } 4575 } 4576 } 4577 4578 log.warning(pos, LintWarnings.LeaksNotAccessibleNotRequiredTransitive(kindName(what), what, what.packge().modle)); 4579 } 4580 } 4581 4582 void checkModuleExists(final DiagnosticPosition pos, ModuleSymbol msym) { 4583 if (msym.kind != MDL) { 4584 log.warning(pos, LintWarnings.ModuleNotFound(msym)); 4585 } 4586 } 4587 4588 void checkPackageExistsForOpens(final DiagnosticPosition pos, PackageSymbol packge) { 4589 if (packge.members().isEmpty() && 4590 ((packge.flags() & Flags.HAS_RESOURCE) == 0)) { 4591 log.warning(pos, LintWarnings.PackageEmptyOrNotFound(packge)); 4592 } 4593 } 4594 4595 void checkModuleRequires(final DiagnosticPosition pos, final RequiresDirective rd) { 4596 if ((rd.module.flags() & Flags.AUTOMATIC_MODULE) != 0) { 4597 if (rd.isTransitive()) { // see comment in Log.applyLint() for special logic that applies 4598 log.warning(pos, LintWarnings.RequiresTransitiveAutomatic); 4599 } else { 4600 log.warning(pos, LintWarnings.RequiresAutomatic); 4601 } 4602 } 4603 } 4604 4605 /** 4606 * Verify the case labels conform to the constraints. Checks constraints related 4607 * combinations of patterns and other labels. 4608 * 4609 * @param cases the cases that should be checked. 4610 */ 4611 void checkSwitchCaseStructure(List<JCCase> cases) { 4612 for (List<JCCase> l = cases; l.nonEmpty(); l = l.tail) { 4613 JCCase c = l.head; 4614 if (c.labels.head instanceof JCConstantCaseLabel constLabel) { 4615 if (TreeInfo.isNull(constLabel.expr)) { 4616 if (c.labels.tail.nonEmpty()) { 4617 if (c.labels.tail.head instanceof JCDefaultCaseLabel defLabel) { 4618 if (c.labels.tail.tail.nonEmpty()) { 4619 log.error(c.labels.tail.tail.head.pos(), Errors.InvalidCaseLabelCombination); 4620 } 4621 } else { 4622 log.error(c.labels.tail.head.pos(), Errors.InvalidCaseLabelCombination); 4623 } 4624 } 4625 } else { 4626 for (JCCaseLabel label : c.labels.tail) { 4627 if (!(label instanceof JCConstantCaseLabel) || TreeInfo.isNullCaseLabel(label)) { 4628 log.error(label.pos(), Errors.InvalidCaseLabelCombination); 4629 break; 4630 } 4631 } 4632 } 4633 } else if (c.labels.tail.nonEmpty()) { 4634 var patterCaseLabels = c.labels.stream().filter(ll -> ll instanceof JCPatternCaseLabel).map(cl -> (JCPatternCaseLabel)cl); 4635 var allUnderscore = patterCaseLabels.allMatch(pcl -> !hasBindings(pcl.getPattern())); 4636 4637 if (!allUnderscore) { 4638 log.error(c.labels.tail.head.pos(), Errors.FlowsThroughFromPattern); 4639 } 4640 4641 boolean allPatternCaseLabels = c.labels.stream().allMatch(p -> p instanceof JCPatternCaseLabel); 4642 4643 if (allPatternCaseLabels) { 4644 preview.checkSourceLevel(c.labels.tail.head.pos(), Feature.UNNAMED_VARIABLES); 4645 } 4646 4647 for (JCCaseLabel label : c.labels.tail) { 4648 if (label instanceof JCConstantCaseLabel) { 4649 log.error(label.pos(), Errors.InvalidCaseLabelCombination); 4650 break; 4651 } 4652 } 4653 } 4654 } 4655 4656 boolean isCaseStatementGroup = cases.nonEmpty() && 4657 cases.head.caseKind == CaseTree.CaseKind.STATEMENT; 4658 4659 if (isCaseStatementGroup) { 4660 boolean previousCompletessNormally = false; 4661 for (List<JCCase> l = cases; l.nonEmpty(); l = l.tail) { 4662 JCCase c = l.head; 4663 if (previousCompletessNormally && 4664 c.stats.nonEmpty() && 4665 c.labels.head instanceof JCPatternCaseLabel patternLabel && 4666 (hasBindings(patternLabel.pat) || hasBindings(c.guard))) { 4667 log.error(c.labels.head.pos(), Errors.FlowsThroughToPattern); 4668 } else if (c.stats.isEmpty() && 4669 c.labels.head instanceof JCPatternCaseLabel patternLabel && 4670 (hasBindings(patternLabel.pat) || hasBindings(c.guard)) && 4671 hasStatements(l.tail)) { 4672 log.error(c.labels.head.pos(), Errors.FlowsThroughFromPattern); 4673 } 4674 previousCompletessNormally = c.completesNormally; 4675 } 4676 } 4677 } 4678 4679 boolean hasBindings(JCTree p) { 4680 boolean[] bindings = new boolean[1]; 4681 4682 new TreeScanner() { 4683 @Override 4684 public void visitBindingPattern(JCBindingPattern tree) { 4685 bindings[0] |= !tree.var.sym.isUnnamedVariable(); 4686 super.visitBindingPattern(tree); 4687 } 4688 }.scan(p); 4689 4690 return bindings[0]; 4691 } 4692 4693 boolean hasStatements(List<JCCase> cases) { 4694 for (List<JCCase> l = cases; l.nonEmpty(); l = l.tail) { 4695 if (l.head.stats.nonEmpty()) { 4696 return true; 4697 } 4698 } 4699 4700 return false; 4701 } 4702 void checkSwitchCaseLabelDominated(JCCaseLabel unconditionalCaseLabel, List<JCCase> cases) { 4703 List<Pair<JCCase, JCCaseLabel>> caseLabels = List.nil(); 4704 boolean seenDefault = false; 4705 boolean seenDefaultLabel = false; 4706 boolean warnDominatedByDefault = false; 4707 boolean unconditionalFound = false; 4708 4709 for (List<JCCase> l = cases; l.nonEmpty(); l = l.tail) { 4710 JCCase c = l.head; 4711 for (JCCaseLabel label : c.labels) { 4712 if (label.hasTag(DEFAULTCASELABEL)) { 4713 seenDefault = true; 4714 seenDefaultLabel |= 4715 TreeInfo.isNullCaseLabel(c.labels.head); 4716 continue; 4717 } 4718 if (TreeInfo.isNullCaseLabel(label)) { 4719 if (seenDefault) { 4720 log.error(label.pos(), Errors.PatternDominated); 4721 } 4722 continue; 4723 } 4724 if (seenDefault && !warnDominatedByDefault) { 4725 if (label.hasTag(PATTERNCASELABEL) || 4726 (label instanceof JCConstantCaseLabel && seenDefaultLabel)) { 4727 log.error(label.pos(), Errors.PatternDominated); 4728 warnDominatedByDefault = true; 4729 } 4730 } 4731 Type currentType = labelType(label); 4732 for (Pair<JCCase, JCCaseLabel> caseAndLabel : caseLabels) { 4733 JCCase testCase = caseAndLabel.fst; 4734 JCCaseLabel testCaseLabel = caseAndLabel.snd; 4735 Type testType = labelType(testCaseLabel); 4736 boolean dominated = false; 4737 if (types.isUnconditionallyExact(currentType, testType) && 4738 !currentType.hasTag(ERROR) && !testType.hasTag(ERROR)) { 4739 //the current label is potentially dominated by the existing (test) label, check: 4740 if (label instanceof JCConstantCaseLabel) { 4741 dominated |= !(testCaseLabel instanceof JCConstantCaseLabel) && 4742 TreeInfo.unguardedCase(testCase); 4743 } else if (label instanceof JCPatternCaseLabel patternCL && 4744 testCaseLabel instanceof JCPatternCaseLabel testPatternCaseLabel && 4745 (testCase.equals(c) || TreeInfo.unguardedCase(testCase))) { 4746 dominated = patternDominated(testPatternCaseLabel.pat, 4747 patternCL.pat); 4748 } 4749 } 4750 4751 if (dominated) { 4752 log.error(label.pos(), Errors.PatternDominated); 4753 } 4754 } 4755 caseLabels = caseLabels.prepend(Pair.of(c, label)); 4756 } 4757 } 4758 } 4759 //where: 4760 private Type labelType(JCCaseLabel label) { 4761 return types.erasure(switch (label.getTag()) { 4762 case PATTERNCASELABEL -> ((JCPatternCaseLabel) label).pat.type; 4763 case CONSTANTCASELABEL -> ((JCConstantCaseLabel) label).expr.type; 4764 default -> throw Assert.error("Unexpected tree kind: " + label.getTag()); 4765 }); 4766 } 4767 private boolean patternDominated(JCPattern existingPattern, JCPattern currentPattern) { 4768 Type existingPatternType = types.erasure(existingPattern.type); 4769 Type currentPatternType = types.erasure(currentPattern.type); 4770 if (!types.isUnconditionallyExact(currentPatternType, existingPatternType)) { 4771 return false; 4772 } 4773 if (currentPattern instanceof JCBindingPattern || 4774 currentPattern instanceof JCAnyPattern) { 4775 return existingPattern instanceof JCBindingPattern || 4776 existingPattern instanceof JCAnyPattern; 4777 } else if (currentPattern instanceof JCRecordPattern currentRecordPattern) { 4778 if (existingPattern instanceof JCBindingPattern || 4779 existingPattern instanceof JCAnyPattern) { 4780 return true; 4781 } else if (existingPattern instanceof JCRecordPattern existingRecordPattern) { 4782 List<JCPattern> existingNested = existingRecordPattern.nested; 4783 List<JCPattern> currentNested = currentRecordPattern.nested; 4784 if (existingNested.size() != currentNested.size()) { 4785 return false; 4786 } 4787 while (existingNested.nonEmpty()) { 4788 if (!patternDominated(existingNested.head, currentNested.head)) { 4789 return false; 4790 } 4791 existingNested = existingNested.tail; 4792 currentNested = currentNested.tail; 4793 } 4794 return true; 4795 } else { 4796 Assert.error("Unknown pattern: " + existingPattern.getTag()); 4797 } 4798 } else { 4799 Assert.error("Unknown pattern: " + currentPattern.getTag()); 4800 } 4801 return false; 4802 } 4803 4804 /** check if a type is a subtype of Externalizable, if that is available. */ 4805 boolean isExternalizable(Type t) { 4806 try { 4807 syms.externalizableType.complete(); 4808 } catch (CompletionFailure e) { 4809 return false; 4810 } 4811 return types.isSubtype(t, syms.externalizableType); 4812 } 4813 4814 /** 4815 * Check structure of serialization declarations. 4816 */ 4817 public void checkSerialStructure(JCClassDecl tree, ClassSymbol c) { 4818 (new SerialTypeVisitor()).visit(c, tree); 4819 } 4820 4821 /** 4822 * This visitor will warn if a serialization-related field or 4823 * method is declared in a suspicious or incorrect way. In 4824 * particular, it will warn for cases where the runtime 4825 * serialization mechanism will silently ignore a mis-declared 4826 * entity. 4827 * 4828 * Distinguished serialization-related fields and methods: 4829 * 4830 * Methods: 4831 * 4832 * private void writeObject(ObjectOutputStream stream) throws IOException 4833 * ANY-ACCESS-MODIFIER Object writeReplace() throws ObjectStreamException 4834 * 4835 * private void readObject(ObjectInputStream stream) throws IOException, ClassNotFoundException 4836 * private void readObjectNoData() throws ObjectStreamException 4837 * ANY-ACCESS-MODIFIER Object readResolve() throws ObjectStreamException 4838 * 4839 * Fields: 4840 * 4841 * private static final long serialVersionUID 4842 * private static final ObjectStreamField[] serialPersistentFields 4843 * 4844 * Externalizable: methods defined on the interface 4845 * public void writeExternal(ObjectOutput) throws IOException 4846 * public void readExternal(ObjectInput) throws IOException 4847 */ 4848 private class SerialTypeVisitor extends ElementKindVisitor14<Void, JCClassDecl> { 4849 SerialTypeVisitor() { 4850 this.lint = Check.this.lint; 4851 } 4852 4853 private static final Set<String> serialMethodNames = 4854 Set.of("writeObject", "writeReplace", 4855 "readObject", "readObjectNoData", 4856 "readResolve"); 4857 4858 private static final Set<String> serialFieldNames = 4859 Set.of("serialVersionUID", "serialPersistentFields"); 4860 4861 // Type of serialPersistentFields 4862 private final Type OSF_TYPE = new Type.ArrayType(syms.objectStreamFieldType, syms.arrayClass); 4863 4864 Lint lint; 4865 4866 @Override 4867 public Void defaultAction(Element e, JCClassDecl p) { 4868 throw new IllegalArgumentException(Objects.requireNonNullElse(e.toString(), "")); 4869 } 4870 4871 @Override 4872 public Void visitType(TypeElement e, JCClassDecl p) { 4873 runUnderLint(e, p, (symbol, param) -> super.visitType(symbol, param)); 4874 return null; 4875 } 4876 4877 @Override 4878 public Void visitTypeAsClass(TypeElement e, 4879 JCClassDecl p) { 4880 // Anonymous classes filtered out by caller. 4881 4882 ClassSymbol c = (ClassSymbol)e; 4883 4884 checkCtorAccess(p, c); 4885 4886 // Check for missing serialVersionUID; check *not* done 4887 // for enums or records. 4888 VarSymbol svuidSym = null; 4889 for (Symbol sym : c.members().getSymbolsByName(names.serialVersionUID)) { 4890 if (sym.kind == VAR) { 4891 svuidSym = (VarSymbol)sym; 4892 break; 4893 } 4894 } 4895 4896 if (svuidSym == null) { 4897 log.warning(p.pos(), LintWarnings.MissingSVUID(c)); 4898 } 4899 4900 // Check for serialPersistentFields to gate checks for 4901 // non-serializable non-transient instance fields 4902 boolean serialPersistentFieldsPresent = 4903 c.members() 4904 .getSymbolsByName(names.serialPersistentFields, sym -> sym.kind == VAR) 4905 .iterator() 4906 .hasNext(); 4907 4908 // Check declarations of serialization-related methods and 4909 // fields 4910 for(Symbol el : c.getEnclosedElements()) { 4911 runUnderLint(el, p, (enclosed, tree) -> { 4912 String name = null; 4913 switch(enclosed.getKind()) { 4914 case FIELD -> { 4915 if (!serialPersistentFieldsPresent) { 4916 var flags = enclosed.flags(); 4917 if ( ((flags & TRANSIENT) == 0) && 4918 ((flags & STATIC) == 0)) { 4919 Type varType = enclosed.asType(); 4920 if (!canBeSerialized(varType)) { 4921 // Note per JLS arrays are 4922 // serializable even if the 4923 // component type is not. 4924 log.warning( 4925 TreeInfo.diagnosticPositionFor(enclosed, tree), 4926 LintWarnings.NonSerializableInstanceField); 4927 } else if (varType.hasTag(ARRAY)) { 4928 ArrayType arrayType = (ArrayType)varType; 4929 Type elementType = arrayType.elemtype; 4930 while (elementType.hasTag(ARRAY)) { 4931 arrayType = (ArrayType)elementType; 4932 elementType = arrayType.elemtype; 4933 } 4934 if (!canBeSerialized(elementType)) { 4935 log.warning( 4936 TreeInfo.diagnosticPositionFor(enclosed, tree), 4937 LintWarnings.NonSerializableInstanceFieldArray(elementType)); 4938 } 4939 } 4940 } 4941 } 4942 4943 name = enclosed.getSimpleName().toString(); 4944 if (serialFieldNames.contains(name)) { 4945 VarSymbol field = (VarSymbol)enclosed; 4946 switch (name) { 4947 case "serialVersionUID" -> checkSerialVersionUID(tree, e, field); 4948 case "serialPersistentFields" -> checkSerialPersistentFields(tree, e, field); 4949 default -> throw new AssertionError(); 4950 } 4951 } 4952 } 4953 4954 // Correctly checking the serialization-related 4955 // methods is subtle. For the methods declared to be 4956 // private or directly declared in the class, the 4957 // enclosed elements of the class can be checked in 4958 // turn. However, writeReplace and readResolve can be 4959 // declared in a superclass and inherited. Note that 4960 // the runtime lookup walks the superclass chain 4961 // looking for writeReplace/readResolve via 4962 // Class.getDeclaredMethod. This differs from calling 4963 // Elements.getAllMembers(TypeElement) as the latter 4964 // will also pull in default methods from 4965 // superinterfaces. In other words, the runtime checks 4966 // (which long predate default methods on interfaces) 4967 // do not admit the possibility of inheriting methods 4968 // this way, a difference from general inheritance. 4969 4970 // The current implementation just checks the enclosed 4971 // elements and does not directly check the inherited 4972 // methods. If all the types are being checked this is 4973 // less of a concern; however, there are cases that 4974 // could be missed. In particular, readResolve and 4975 // writeReplace could, in principle, by inherited from 4976 // a non-serializable superclass and thus not checked 4977 // even if compiled with a serializable child class. 4978 case METHOD -> { 4979 var method = (MethodSymbol)enclosed; 4980 name = method.getSimpleName().toString(); 4981 if (serialMethodNames.contains(name)) { 4982 switch (name) { 4983 case "writeObject" -> checkWriteObject(tree, e, method); 4984 case "writeReplace" -> checkWriteReplace(tree,e, method); 4985 case "readObject" -> checkReadObject(tree,e, method); 4986 case "readObjectNoData" -> checkReadObjectNoData(tree, e, method); 4987 case "readResolve" -> checkReadResolve(tree, e, method); 4988 default -> throw new AssertionError(); 4989 } 4990 } 4991 } 4992 } 4993 }); 4994 } 4995 4996 return null; 4997 } 4998 4999 boolean canBeSerialized(Type type) { 5000 return type.isPrimitive() || rs.isSerializable(type); 5001 } 5002 5003 /** 5004 * Check that Externalizable class needs a public no-arg 5005 * constructor. 5006 * 5007 * Check that a Serializable class has access to the no-arg 5008 * constructor of its first nonserializable superclass. 5009 */ 5010 private void checkCtorAccess(JCClassDecl tree, ClassSymbol c) { 5011 if (isExternalizable(c.type)) { 5012 for(var sym : c.getEnclosedElements()) { 5013 if (sym.isConstructor() && 5014 ((sym.flags() & PUBLIC) == PUBLIC)) { 5015 if (((MethodSymbol)sym).getParameters().isEmpty()) { 5016 return; 5017 } 5018 } 5019 } 5020 log.warning(tree.pos(), 5021 LintWarnings.ExternalizableMissingPublicNoArgCtor); 5022 } else { 5023 // Approximate access to the no-arg constructor up in 5024 // the superclass chain by checking that the 5025 // constructor is not private. This may not handle 5026 // some cross-package situations correctly. 5027 Type superClass = c.getSuperclass(); 5028 // java.lang.Object is *not* Serializable so this loop 5029 // should terminate. 5030 while (rs.isSerializable(superClass) ) { 5031 try { 5032 superClass = (Type)((TypeElement)(((DeclaredType)superClass)).asElement()).getSuperclass(); 5033 } catch(ClassCastException cce) { 5034 return ; // Don't try to recover 5035 } 5036 } 5037 // Non-Serializable superclass 5038 try { 5039 ClassSymbol supertype = ((ClassSymbol)(((DeclaredType)superClass).asElement())); 5040 for(var sym : supertype.getEnclosedElements()) { 5041 if (sym.isConstructor()) { 5042 MethodSymbol ctor = (MethodSymbol)sym; 5043 if (ctor.getParameters().isEmpty()) { 5044 if (((ctor.flags() & PRIVATE) == PRIVATE) || 5045 // Handle nested classes and implicit this$0 5046 (supertype.getNestingKind() == NestingKind.MEMBER && 5047 ((supertype.flags() & STATIC) == 0))) 5048 log.warning(tree.pos(), 5049 LintWarnings.SerializableMissingAccessNoArgCtor(supertype.getQualifiedName())); 5050 } 5051 } 5052 } 5053 } catch (ClassCastException cce) { 5054 return ; // Don't try to recover 5055 } 5056 return; 5057 } 5058 } 5059 5060 private void checkSerialVersionUID(JCClassDecl tree, Element e, VarSymbol svuid) { 5061 // To be effective, serialVersionUID must be marked static 5062 // and final, but private is recommended. But alas, in 5063 // practice there are many non-private serialVersionUID 5064 // fields. 5065 if ((svuid.flags() & (STATIC | FINAL)) != 5066 (STATIC | FINAL)) { 5067 log.warning( 5068 TreeInfo.diagnosticPositionFor(svuid, tree), 5069 LintWarnings.ImproperSVUID((Symbol)e)); 5070 } 5071 5072 // check svuid has type long 5073 if (!svuid.type.hasTag(LONG)) { 5074 log.warning( 5075 TreeInfo.diagnosticPositionFor(svuid, tree), 5076 LintWarnings.LongSVUID((Symbol)e)); 5077 } 5078 5079 if (svuid.getConstValue() == null) 5080 log.warning( 5081 TreeInfo.diagnosticPositionFor(svuid, tree), 5082 LintWarnings.ConstantSVUID((Symbol)e)); 5083 } 5084 5085 private void checkSerialPersistentFields(JCClassDecl tree, Element e, VarSymbol spf) { 5086 // To be effective, serialPersisentFields must be private, static, and final. 5087 if ((spf.flags() & (PRIVATE | STATIC | FINAL)) != 5088 (PRIVATE | STATIC | FINAL)) { 5089 log.warning( 5090 TreeInfo.diagnosticPositionFor(spf, tree), 5091 LintWarnings.ImproperSPF); 5092 } 5093 5094 if (!types.isSameType(spf.type, OSF_TYPE)) { 5095 log.warning( 5096 TreeInfo.diagnosticPositionFor(spf, tree), 5097 LintWarnings.OSFArraySPF); 5098 } 5099 5100 if (isExternalizable((Type)(e.asType()))) { 5101 log.warning( 5102 TreeInfo.diagnosticPositionFor(spf, tree), 5103 LintWarnings.IneffectualSerialFieldExternalizable); 5104 } 5105 5106 // Warn if serialPersistentFields is initialized to a 5107 // literal null. 5108 JCTree spfDecl = TreeInfo.declarationFor(spf, tree); 5109 if (spfDecl != null && spfDecl.getTag() == VARDEF) { 5110 JCVariableDecl variableDef = (JCVariableDecl) spfDecl; 5111 JCExpression initExpr = variableDef.init; 5112 if (initExpr != null && TreeInfo.isNull(initExpr)) { 5113 log.warning(initExpr.pos(), 5114 LintWarnings.SPFNullInit); 5115 } 5116 } 5117 } 5118 5119 private void checkWriteObject(JCClassDecl tree, Element e, MethodSymbol method) { 5120 // The "synchronized" modifier is seen in the wild on 5121 // readObject and writeObject methods and is generally 5122 // innocuous. 5123 5124 // private void writeObject(ObjectOutputStream stream) throws IOException 5125 checkPrivateNonStaticMethod(tree, method); 5126 checkReturnType(tree, e, method, syms.voidType); 5127 checkOneArg(tree, e, method, syms.objectOutputStreamType); 5128 checkExceptions(tree, e, method, syms.ioExceptionType); 5129 checkExternalizable(tree, e, method); 5130 } 5131 5132 private void checkWriteReplace(JCClassDecl tree, Element e, MethodSymbol method) { 5133 // ANY-ACCESS-MODIFIER Object writeReplace() throws 5134 // ObjectStreamException 5135 5136 // Excluding abstract, could have a more complicated 5137 // rule based on abstract-ness of the class 5138 checkConcreteInstanceMethod(tree, e, method); 5139 checkReturnType(tree, e, method, syms.objectType); 5140 checkNoArgs(tree, e, method); 5141 checkExceptions(tree, e, method, syms.objectStreamExceptionType); 5142 } 5143 5144 private void checkReadObject(JCClassDecl tree, Element e, MethodSymbol method) { 5145 // The "synchronized" modifier is seen in the wild on 5146 // readObject and writeObject methods and is generally 5147 // innocuous. 5148 5149 // private void readObject(ObjectInputStream stream) 5150 // throws IOException, ClassNotFoundException 5151 checkPrivateNonStaticMethod(tree, method); 5152 checkReturnType(tree, e, method, syms.voidType); 5153 checkOneArg(tree, e, method, syms.objectInputStreamType); 5154 checkExceptions(tree, e, method, syms.ioExceptionType, syms.classNotFoundExceptionType); 5155 checkExternalizable(tree, e, method); 5156 } 5157 5158 private void checkReadObjectNoData(JCClassDecl tree, Element e, MethodSymbol method) { 5159 // private void readObjectNoData() throws ObjectStreamException 5160 checkPrivateNonStaticMethod(tree, method); 5161 checkReturnType(tree, e, method, syms.voidType); 5162 checkNoArgs(tree, e, method); 5163 checkExceptions(tree, e, method, syms.objectStreamExceptionType); 5164 checkExternalizable(tree, e, method); 5165 } 5166 5167 private void checkReadResolve(JCClassDecl tree, Element e, MethodSymbol method) { 5168 // ANY-ACCESS-MODIFIER Object readResolve() 5169 // throws ObjectStreamException 5170 5171 // Excluding abstract, could have a more complicated 5172 // rule based on abstract-ness of the class 5173 checkConcreteInstanceMethod(tree, e, method); 5174 checkReturnType(tree,e, method, syms.objectType); 5175 checkNoArgs(tree, e, method); 5176 checkExceptions(tree, e, method, syms.objectStreamExceptionType); 5177 } 5178 5179 private void checkWriteExternalRecord(JCClassDecl tree, Element e, MethodSymbol method, boolean isExtern) { 5180 //public void writeExternal(ObjectOutput) throws IOException 5181 checkExternMethodRecord(tree, e, method, syms.objectOutputType, isExtern); 5182 } 5183 5184 private void checkReadExternalRecord(JCClassDecl tree, Element e, MethodSymbol method, boolean isExtern) { 5185 // public void readExternal(ObjectInput) throws IOException 5186 checkExternMethodRecord(tree, e, method, syms.objectInputType, isExtern); 5187 } 5188 5189 private void checkExternMethodRecord(JCClassDecl tree, Element e, MethodSymbol method, Type argType, 5190 boolean isExtern) { 5191 if (isExtern && isExternMethod(tree, e, method, argType)) { 5192 log.warning( 5193 TreeInfo.diagnosticPositionFor(method, tree), 5194 LintWarnings.IneffectualExternalizableMethodRecord(method.getSimpleName().toString())); 5195 } 5196 } 5197 5198 void checkPrivateNonStaticMethod(JCClassDecl tree, MethodSymbol method) { 5199 var flags = method.flags(); 5200 if ((flags & PRIVATE) == 0) { 5201 log.warning( 5202 TreeInfo.diagnosticPositionFor(method, tree), 5203 LintWarnings.SerialMethodNotPrivate(method.getSimpleName())); 5204 } 5205 5206 if ((flags & STATIC) != 0) { 5207 log.warning( 5208 TreeInfo.diagnosticPositionFor(method, tree), 5209 LintWarnings.SerialMethodStatic(method.getSimpleName())); 5210 } 5211 } 5212 5213 /** 5214 * Per section 1.12 "Serialization of Enum Constants" of 5215 * the serialization specification, due to the special 5216 * serialization handling of enums, any writeObject, 5217 * readObject, writeReplace, and readResolve methods are 5218 * ignored as are serialPersistentFields and 5219 * serialVersionUID fields. 5220 */ 5221 @Override 5222 public Void visitTypeAsEnum(TypeElement e, 5223 JCClassDecl p) { 5224 boolean isExtern = isExternalizable((Type)e.asType()); 5225 for(Element el : e.getEnclosedElements()) { 5226 runUnderLint(el, p, (enclosed, tree) -> { 5227 String name = enclosed.getSimpleName().toString(); 5228 switch(enclosed.getKind()) { 5229 case FIELD -> { 5230 var field = (VarSymbol)enclosed; 5231 if (serialFieldNames.contains(name)) { 5232 log.warning( 5233 TreeInfo.diagnosticPositionFor(field, tree), 5234 LintWarnings.IneffectualSerialFieldEnum(name)); 5235 } 5236 } 5237 5238 case METHOD -> { 5239 var method = (MethodSymbol)enclosed; 5240 if (serialMethodNames.contains(name)) { 5241 log.warning( 5242 TreeInfo.diagnosticPositionFor(method, tree), 5243 LintWarnings.IneffectualSerialMethodEnum(name)); 5244 } 5245 5246 if (isExtern) { 5247 switch(name) { 5248 case "writeExternal" -> checkWriteExternalEnum(tree, e, method); 5249 case "readExternal" -> checkReadExternalEnum(tree, e, method); 5250 } 5251 } 5252 } 5253 5254 // Also perform checks on any class bodies of enum constants, see JLS 8.9.1. 5255 case ENUM_CONSTANT -> { 5256 var field = (VarSymbol)enclosed; 5257 JCVariableDecl decl = (JCVariableDecl) TreeInfo.declarationFor(field, p); 5258 if (decl.init instanceof JCNewClass nc && nc.def != null) { 5259 ClassSymbol enumConstantType = nc.def.sym; 5260 visitTypeAsEnum(enumConstantType, p); 5261 } 5262 } 5263 5264 }}); 5265 } 5266 return null; 5267 } 5268 5269 private void checkWriteExternalEnum(JCClassDecl tree, Element e, MethodSymbol method) { 5270 //public void writeExternal(ObjectOutput) throws IOException 5271 checkExternMethodEnum(tree, e, method, syms.objectOutputType); 5272 } 5273 5274 private void checkReadExternalEnum(JCClassDecl tree, Element e, MethodSymbol method) { 5275 // public void readExternal(ObjectInput) throws IOException 5276 checkExternMethodEnum(tree, e, method, syms.objectInputType); 5277 } 5278 5279 private void checkExternMethodEnum(JCClassDecl tree, Element e, MethodSymbol method, Type argType) { 5280 if (isExternMethod(tree, e, method, argType)) { 5281 log.warning( 5282 TreeInfo.diagnosticPositionFor(method, tree), 5283 LintWarnings.IneffectualExternMethodEnum(method.getSimpleName().toString())); 5284 } 5285 } 5286 5287 private boolean isExternMethod(JCClassDecl tree, Element e, MethodSymbol method, Type argType) { 5288 long flags = method.flags(); 5289 Type rtype = method.getReturnType(); 5290 5291 // Not necessary to check throws clause in this context 5292 return (flags & PUBLIC) != 0 && (flags & STATIC) == 0 && 5293 types.isSameType(syms.voidType, rtype) && 5294 hasExactlyOneArgWithType(tree, e, method, argType); 5295 } 5296 5297 /** 5298 * Most serialization-related fields and methods on interfaces 5299 * are ineffectual or problematic. 5300 */ 5301 @Override 5302 public Void visitTypeAsInterface(TypeElement e, 5303 JCClassDecl p) { 5304 for(Element el : e.getEnclosedElements()) { 5305 runUnderLint(el, p, (enclosed, tree) -> { 5306 String name = null; 5307 switch(enclosed.getKind()) { 5308 case FIELD -> { 5309 var field = (VarSymbol)enclosed; 5310 name = field.getSimpleName().toString(); 5311 switch(name) { 5312 case "serialPersistentFields" -> { 5313 log.warning( 5314 TreeInfo.diagnosticPositionFor(field, tree), 5315 LintWarnings.IneffectualSerialFieldInterface); 5316 } 5317 5318 case "serialVersionUID" -> { 5319 checkSerialVersionUID(tree, e, field); 5320 } 5321 } 5322 } 5323 5324 case METHOD -> { 5325 var method = (MethodSymbol)enclosed; 5326 name = enclosed.getSimpleName().toString(); 5327 if (serialMethodNames.contains(name)) { 5328 switch (name) { 5329 case 5330 "readObject", 5331 "readObjectNoData", 5332 "writeObject" -> checkPrivateMethod(tree, e, method); 5333 5334 case 5335 "writeReplace", 5336 "readResolve" -> checkDefaultIneffective(tree, e, method); 5337 5338 default -> throw new AssertionError(); 5339 } 5340 5341 } 5342 }} 5343 }); 5344 } 5345 5346 return null; 5347 } 5348 5349 private void checkPrivateMethod(JCClassDecl tree, 5350 Element e, 5351 MethodSymbol method) { 5352 if ((method.flags() & PRIVATE) == 0) { 5353 log.warning( 5354 TreeInfo.diagnosticPositionFor(method, tree), 5355 LintWarnings.NonPrivateMethodWeakerAccess); 5356 } 5357 } 5358 5359 private void checkDefaultIneffective(JCClassDecl tree, 5360 Element e, 5361 MethodSymbol method) { 5362 if ((method.flags() & DEFAULT) == DEFAULT) { 5363 log.warning( 5364 TreeInfo.diagnosticPositionFor(method, tree), 5365 LintWarnings.DefaultIneffective); 5366 5367 } 5368 } 5369 5370 @Override 5371 public Void visitTypeAsAnnotationType(TypeElement e, 5372 JCClassDecl p) { 5373 // Per the JLS, annotation types are not serializeable 5374 return null; 5375 } 5376 5377 /** 5378 * From the Java Object Serialization Specification, 1.13 5379 * Serialization of Records: 5380 * 5381 * "The process by which record objects are serialized or 5382 * externalized cannot be customized; any class-specific 5383 * writeObject, readObject, readObjectNoData, writeExternal, 5384 * and readExternal methods defined by record classes are 5385 * ignored during serialization and deserialization. However, 5386 * a substitute object to be serialized or a designate 5387 * replacement may be specified, by the writeReplace and 5388 * readResolve methods, respectively. Any 5389 * serialPersistentFields field declaration is 5390 * ignored. Documenting serializable fields and data for 5391 * record classes is unnecessary, since there is no variation 5392 * in the serial form, other than whether a substitute or 5393 * replacement object is used. The serialVersionUID of a 5394 * record class is 0L unless explicitly declared. The 5395 * requirement for matching serialVersionUID values is waived 5396 * for record classes." 5397 */ 5398 @Override 5399 public Void visitTypeAsRecord(TypeElement e, 5400 JCClassDecl p) { 5401 boolean isExtern = isExternalizable((Type)e.asType()); 5402 for(Element el : e.getEnclosedElements()) { 5403 runUnderLint(el, p, (enclosed, tree) -> { 5404 String name = enclosed.getSimpleName().toString(); 5405 switch(enclosed.getKind()) { 5406 case FIELD -> { 5407 var field = (VarSymbol)enclosed; 5408 switch(name) { 5409 case "serialPersistentFields" -> { 5410 log.warning( 5411 TreeInfo.diagnosticPositionFor(field, tree), 5412 LintWarnings.IneffectualSerialFieldRecord); 5413 } 5414 5415 case "serialVersionUID" -> { 5416 // Could generate additional warning that 5417 // svuid value is not checked to match for 5418 // records. 5419 checkSerialVersionUID(tree, e, field); 5420 }} 5421 } 5422 5423 case METHOD -> { 5424 var method = (MethodSymbol)enclosed; 5425 switch(name) { 5426 case "writeReplace" -> checkWriteReplace(tree, e, method); 5427 case "readResolve" -> checkReadResolve(tree, e, method); 5428 5429 case "writeExternal" -> checkWriteExternalRecord(tree, e, method, isExtern); 5430 case "readExternal" -> checkReadExternalRecord(tree, e, method, isExtern); 5431 5432 default -> { 5433 if (serialMethodNames.contains(name)) { 5434 log.warning( 5435 TreeInfo.diagnosticPositionFor(method, tree), 5436 LintWarnings.IneffectualSerialMethodRecord(name)); 5437 } 5438 }} 5439 }}}); 5440 } 5441 return null; 5442 } 5443 5444 void checkConcreteInstanceMethod(JCClassDecl tree, 5445 Element enclosing, 5446 MethodSymbol method) { 5447 if ((method.flags() & (STATIC | ABSTRACT)) != 0) { 5448 log.warning( 5449 TreeInfo.diagnosticPositionFor(method, tree), 5450 LintWarnings.SerialConcreteInstanceMethod(method.getSimpleName())); 5451 } 5452 } 5453 5454 private void checkReturnType(JCClassDecl tree, 5455 Element enclosing, 5456 MethodSymbol method, 5457 Type expectedReturnType) { 5458 // Note: there may be complications checking writeReplace 5459 // and readResolve since they return Object and could, in 5460 // principle, have covariant overrides and any synthetic 5461 // bridge method would not be represented here for 5462 // checking. 5463 Type rtype = method.getReturnType(); 5464 if (!types.isSameType(expectedReturnType, rtype)) { 5465 log.warning( 5466 TreeInfo.diagnosticPositionFor(method, tree), 5467 LintWarnings.SerialMethodUnexpectedReturnType(method.getSimpleName(), 5468 rtype, expectedReturnType)); 5469 } 5470 } 5471 5472 private void checkOneArg(JCClassDecl tree, 5473 Element enclosing, 5474 MethodSymbol method, 5475 Type expectedType) { 5476 String name = method.getSimpleName().toString(); 5477 5478 var parameters= method.getParameters(); 5479 5480 if (parameters.size() != 1) { 5481 log.warning( 5482 TreeInfo.diagnosticPositionFor(method, tree), 5483 LintWarnings.SerialMethodOneArg(method.getSimpleName(), parameters.size())); 5484 return; 5485 } 5486 5487 Type parameterType = parameters.get(0).asType(); 5488 if (!types.isSameType(parameterType, expectedType)) { 5489 log.warning( 5490 TreeInfo.diagnosticPositionFor(method, tree), 5491 LintWarnings.SerialMethodParameterType(method.getSimpleName(), 5492 expectedType, 5493 parameterType)); 5494 } 5495 } 5496 5497 private boolean hasExactlyOneArgWithType(JCClassDecl tree, 5498 Element enclosing, 5499 MethodSymbol method, 5500 Type expectedType) { 5501 var parameters = method.getParameters(); 5502 return (parameters.size() == 1) && 5503 types.isSameType(parameters.get(0).asType(), expectedType); 5504 } 5505 5506 5507 private void checkNoArgs(JCClassDecl tree, Element enclosing, MethodSymbol method) { 5508 var parameters = method.getParameters(); 5509 if (!parameters.isEmpty()) { 5510 log.warning( 5511 TreeInfo.diagnosticPositionFor(parameters.get(0), tree), 5512 LintWarnings.SerialMethodNoArgs(method.getSimpleName())); 5513 } 5514 } 5515 5516 private void checkExternalizable(JCClassDecl tree, Element enclosing, MethodSymbol method) { 5517 // If the enclosing class is externalizable, warn for the method 5518 if (isExternalizable((Type)enclosing.asType())) { 5519 log.warning( 5520 TreeInfo.diagnosticPositionFor(method, tree), 5521 LintWarnings.IneffectualSerialMethodExternalizable(method.getSimpleName())); 5522 } 5523 return; 5524 } 5525 5526 private void checkExceptions(JCClassDecl tree, 5527 Element enclosing, 5528 MethodSymbol method, 5529 Type... declaredExceptions) { 5530 for (Type thrownType: method.getThrownTypes()) { 5531 // For each exception in the throws clause of the 5532 // method, if not an Error and not a RuntimeException, 5533 // check if the exception is a subtype of a declared 5534 // exception from the throws clause of the 5535 // serialization method in question. 5536 if (types.isSubtype(thrownType, syms.runtimeExceptionType) || 5537 types.isSubtype(thrownType, syms.errorType) ) { 5538 continue; 5539 } else { 5540 boolean declared = false; 5541 for (Type declaredException : declaredExceptions) { 5542 if (types.isSubtype(thrownType, declaredException)) { 5543 declared = true; 5544 continue; 5545 } 5546 } 5547 if (!declared) { 5548 log.warning( 5549 TreeInfo.diagnosticPositionFor(method, tree), 5550 LintWarnings.SerialMethodUnexpectedException(method.getSimpleName(), 5551 thrownType)); 5552 } 5553 } 5554 } 5555 return; 5556 } 5557 5558 private <E extends Element> Void runUnderLint(E symbol, JCClassDecl p, BiConsumer<E, JCClassDecl> task) { 5559 Lint prevLint = lint; 5560 try { 5561 lint = lint.augment((Symbol) symbol); 5562 5563 if (lint.isEnabled(LintCategory.SERIAL)) { 5564 task.accept(symbol, p); 5565 } 5566 5567 return null; 5568 } finally { 5569 lint = prevLint; 5570 } 5571 } 5572 5573 } 5574 5575 void checkRequiresIdentity(JCTree tree, Lint lint) { 5576 switch (tree) { 5577 case JCClassDecl classDecl -> { 5578 Type st = types.supertype(classDecl.sym.type); 5579 if (st != null && 5580 // no need to recheck j.l.Object, shortcut, 5581 st.tsym != syms.objectType.tsym && 5582 // this one could be null, no explicit extends 5583 classDecl.extending != null) { 5584 checkIfIdentityIsExpected(classDecl.extending.pos(), st, lint); 5585 } 5586 for (JCExpression intrface: classDecl.implementing) { 5587 checkIfIdentityIsExpected(intrface.pos(), intrface.type, lint); 5588 } 5589 for (JCTypeParameter tp : classDecl.typarams) { 5590 checkIfIdentityIsExpected(tp.pos(), tp.type, lint); 5591 } 5592 } 5593 case JCVariableDecl variableDecl -> { 5594 if (variableDecl.vartype != null && 5595 (variableDecl.sym.flags_field & RECORD) == 0 || 5596 (variableDecl.sym.flags_field & ~(Flags.PARAMETER | RECORD | GENERATED_MEMBER)) != 0) { 5597 /* we don't want to warn twice so if this variable is a compiler generated parameter of 5598 * a canonical record constructor, we don't want to issue a warning as we will warn the 5599 * corresponding compiler generated private record field anyways 5600 */ 5601 checkIfIdentityIsExpected(variableDecl.vartype.pos(), variableDecl.vartype.type, lint); 5602 } 5603 } 5604 case JCTypeCast typeCast -> checkIfIdentityIsExpected(typeCast.clazz.pos(), typeCast.clazz.type, lint); 5605 case JCBindingPattern bindingPattern -> { 5606 if (bindingPattern.var.vartype != null) { 5607 checkIfIdentityIsExpected(bindingPattern.var.vartype.pos(), bindingPattern.var.vartype.type, lint); 5608 } 5609 } 5610 case JCMethodDecl methodDecl -> { 5611 for (JCTypeParameter tp : methodDecl.typarams) { 5612 checkIfIdentityIsExpected(tp.pos(), tp.type, lint); 5613 } 5614 if (methodDecl.restype != null && !methodDecl.restype.type.hasTag(VOID)) { 5615 checkIfIdentityIsExpected(methodDecl.restype.pos(), methodDecl.restype.type, lint); 5616 } 5617 } 5618 case JCMemberReference mref -> { 5619 checkIfIdentityIsExpected(mref.expr.pos(), mref.target, lint); 5620 checkIfTypeParamsRequiresIdentity(mref.sym.getMetadata(), mref.typeargs, lint); 5621 } 5622 case JCPolyExpression poly 5623 when (poly instanceof JCNewClass || poly instanceof JCMethodInvocation) -> { 5624 if (poly instanceof JCNewClass newClass) { 5625 checkIfIdentityIsExpected(newClass.clazz.pos(), newClass.clazz.type, lint); 5626 } 5627 List<JCExpression> argExps = poly instanceof JCNewClass ? 5628 ((JCNewClass)poly).args : 5629 ((JCMethodInvocation)poly).args; 5630 Symbol msym = TreeInfo.symbolFor(poly); 5631 if (msym != null) { 5632 if (!argExps.isEmpty() && msym instanceof MethodSymbol ms && ms.params != null) { 5633 VarSymbol lastParam = ms.params.head; 5634 for (VarSymbol param: ms.params) { 5635 if ((param.flags_field & REQUIRES_IDENTITY) != 0 && argExps.head.type.isValueBased()) { 5636 log.warning(argExps.head.pos(), LintWarnings.AttemptToUseValueBasedWhereIdentityExpected); 5637 } 5638 lastParam = param; 5639 argExps = argExps.tail; 5640 } 5641 while (argExps != null && !argExps.isEmpty() && lastParam != null) { 5642 if ((lastParam.flags_field & REQUIRES_IDENTITY) != 0 && argExps.head.type.isValueBased()) { 5643 log.warning(argExps.head.pos(), LintWarnings.AttemptToUseValueBasedWhereIdentityExpected); 5644 } 5645 argExps = argExps.tail; 5646 } 5647 } 5648 checkIfTypeParamsRequiresIdentity( 5649 msym.getMetadata(), 5650 poly instanceof JCNewClass ? 5651 ((JCNewClass)poly).typeargs : 5652 ((JCMethodInvocation)poly).typeargs, 5653 lint); 5654 } 5655 } 5656 default -> throw new AssertionError("unexpected tree " + tree); 5657 } 5658 } 5659 5660 /** Check if a type required an identity class 5661 */ 5662 private boolean checkIfIdentityIsExpected(DiagnosticPosition pos, Type t, Lint lint) { 5663 if (t != null && 5664 lint != null && 5665 lint.isEnabled(LintCategory.IDENTITY)) { 5666 RequiresIdentityVisitor requiresIdentityVisitor = new RequiresIdentityVisitor(); 5667 // we need to avoid recursion due to self referencing type vars or captures, this is why we need a set 5668 requiresIdentityVisitor.visit(t, new HashSet<>()); 5669 if (requiresIdentityVisitor.requiresWarning) { 5670 log.warning(pos, LintWarnings.AttemptToUseValueBasedWhereIdentityExpected); 5671 return true; 5672 } 5673 } 5674 return false; 5675 } 5676 5677 // where 5678 private class RequiresIdentityVisitor extends Types.SimpleVisitor<Void, Set<Type>> { 5679 boolean requiresWarning = false; 5680 5681 @Override 5682 public Void visitType(Type t, Set<Type> seen) { 5683 return null; 5684 } 5685 5686 @Override 5687 public Void visitWildcardType(WildcardType t, Set<Type> seen) { 5688 return visit(t.type, seen); 5689 } 5690 5691 @Override 5692 public Void visitTypeVar(TypeVar t, Set<Type> seen) { 5693 if (seen.add(t)) { 5694 visit(t.getUpperBound(), seen); 5695 } 5696 return null; 5697 } 5698 5699 @Override 5700 public Void visitCapturedType(CapturedType t, Set<Type> seen) { 5701 if (seen.add(t)) { 5702 visit(t.getUpperBound(), seen); 5703 visit(t.getLowerBound(), seen); 5704 } 5705 return null; 5706 } 5707 5708 @Override 5709 public Void visitArrayType(ArrayType t, Set<Type> seen) { 5710 return visit(t.elemtype, seen); 5711 } 5712 5713 @Override 5714 public Void visitClassType(ClassType t, Set<Type> seen) { 5715 if (t != null && t.tsym != null) { 5716 SymbolMetadata sm = t.tsym.getMetadata(); 5717 if (sm != null && !t.getTypeArguments().isEmpty()) { 5718 if (sm.getTypeAttributes().stream() 5719 .filter(ta -> isRequiresIdentityAnnotation(ta.type.tsym) && 5720 t.getTypeArguments().get(ta.position.parameter_index) != null && 5721 t.getTypeArguments().get(ta.position.parameter_index).isValueBased()).findAny().isPresent()) { 5722 requiresWarning = true; 5723 return null; 5724 } 5725 } 5726 } 5727 visit(t.getEnclosingType(), seen); 5728 for (Type targ : t.getTypeArguments()) { 5729 visit(targ, seen); 5730 } 5731 return null; 5732 } 5733 } // RequiresIdentityVisitor 5734 5735 private void checkIfTypeParamsRequiresIdentity(SymbolMetadata sm, 5736 List<JCExpression> typeParamTrees, 5737 Lint lint) { 5738 if (typeParamTrees != null && !typeParamTrees.isEmpty()) { 5739 for (JCExpression targ : typeParamTrees) { 5740 checkIfIdentityIsExpected(targ.pos(), targ.type, lint); 5741 } 5742 if (sm != null) 5743 sm.getTypeAttributes().stream() 5744 .filter(ta -> isRequiresIdentityAnnotation(ta.type.tsym) && 5745 typeParamTrees.get(ta.position.parameter_index).type != null && 5746 typeParamTrees.get(ta.position.parameter_index).type.isValueBased()) 5747 .forEach(ta -> log.warning(typeParamTrees.get(ta.position.parameter_index).pos(), 5748 CompilerProperties.LintWarnings.AttemptToUseValueBasedWhereIdentityExpected)); 5749 } 5750 } 5751 5752 private boolean isRequiresIdentityAnnotation(TypeSymbol annoType) { 5753 return annoType == syms.requiresIdentityType.tsym || 5754 annoType.flatName() == syms.requiresIdentityInternalType.tsym.flatName(); 5755 } 5756 }