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