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