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 : ExtendedVarFlags; 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 // Interfaces are always ABSTRACT 1334 if ((flags & INTERFACE) != 0) implicit |= ABSTRACT; 1335 1336 if ((flags & (INTERFACE | VALUE_CLASS)) == 0) { 1337 implicit |= IDENTITY_TYPE; 1338 } 1339 1340 if ((flags & ENUM) != 0) { 1341 // enums can't be declared abstract, final, sealed or non-sealed or value 1342 mask &= ~(ABSTRACT | FINAL | SEALED | NON_SEALED | VALUE_CLASS); 1343 implicit |= implicitEnumFinalFlag(tree); 1344 } 1345 if ((flags & RECORD) != 0) { 1346 // records can't be declared abstract 1347 mask &= ~ABSTRACT; 1348 implicit |= FINAL; 1349 } 1350 if ((flags & STRICTFP) != 0) { 1351 warnOnExplicitStrictfp(pos); 1352 } 1353 // Imply STRICTFP if owner has STRICTFP set. 1354 implicit |= sym.owner.flags_field & STRICTFP; 1355 1356 // concrete value classes are implicitly final 1357 if ((flags & (ABSTRACT | INTERFACE | VALUE_CLASS)) == VALUE_CLASS) { 1358 implicit |= FINAL; 1359 } 1360 break; 1361 default: 1362 throw new AssertionError(); 1363 } 1364 long illegal = flags & ExtendedStandardFlags & ~mask; 1365 if (illegal != 0) { 1366 if ((illegal & INTERFACE) != 0) { 1367 log.error(pos, ((flags & ANNOTATION) != 0) ? Errors.AnnotationDeclNotAllowedHere : Errors.IntfNotAllowedHere); 1368 mask |= INTERFACE; 1369 } 1370 else { 1371 log.error(pos, 1372 Errors.ModNotAllowedHere(asFlagSet(illegal))); 1373 } 1374 } 1375 else if ((sym.kind == TYP || 1376 // ISSUE: Disallowing abstract&private is no longer appropriate 1377 // in the presence of inner classes. Should it be deleted here? 1378 checkDisjoint(pos, flags, 1379 ABSTRACT, 1380 PRIVATE | STATIC | DEFAULT)) 1381 && 1382 checkDisjoint(pos, flags, 1383 STATIC | PRIVATE, 1384 DEFAULT) 1385 && 1386 checkDisjoint(pos, flags, 1387 ABSTRACT | INTERFACE, 1388 FINAL | NATIVE | SYNCHRONIZED) 1389 && 1390 checkDisjoint(pos, flags, 1391 PUBLIC, 1392 PRIVATE | PROTECTED) 1393 && 1394 checkDisjoint(pos, flags, 1395 PRIVATE, 1396 PUBLIC | PROTECTED) 1397 && 1398 checkDisjoint(pos, flags, 1399 FINAL, 1400 VOLATILE) 1401 && 1402 (sym.kind == TYP || 1403 checkDisjoint(pos, flags, 1404 ABSTRACT | NATIVE, 1405 STRICTFP)) 1406 && checkDisjoint(pos, flags, 1407 FINAL, 1408 SEALED | NON_SEALED) 1409 && checkDisjoint(pos, flags, 1410 SEALED, 1411 FINAL | NON_SEALED) 1412 && checkDisjoint(pos, flags, 1413 SEALED, 1414 ANNOTATION) 1415 && checkDisjoint(pos, flags, 1416 VALUE_CLASS, 1417 ANNOTATION) 1418 && checkDisjoint(pos, flags, 1419 VALUE_CLASS, 1420 NON_SEALED) 1421 && checkDisjoint(pos, flags, 1422 VALUE_CLASS, 1423 INTERFACE) ) { 1424 // skip 1425 } 1426 return flags & (mask | ~ExtendedStandardFlags) | implicit; 1427 } 1428 1429 private void warnOnExplicitStrictfp(DiagnosticPosition pos) { 1430 DiagnosticPosition prevLintPos = deferredLintHandler.setPos(pos); 1431 try { 1432 deferredLintHandler.report(_l -> { 1433 if (lint.isEnabled(LintCategory.STRICTFP)) { 1434 log.warning(LintCategory.STRICTFP, 1435 pos, Warnings.Strictfp); } 1436 }); 1437 } finally { 1438 deferredLintHandler.setPos(prevLintPos); 1439 } 1440 } 1441 1442 1443 /** Determine if this enum should be implicitly final. 1444 * 1445 * If the enum has no specialized enum constants, it is final. 1446 * 1447 * If the enum does have specialized enum constants, it is 1448 * <i>not</i> final. 1449 */ 1450 private long implicitEnumFinalFlag(JCTree tree) { 1451 if (!tree.hasTag(CLASSDEF)) return 0; 1452 class SpecialTreeVisitor extends JCTree.Visitor { 1453 boolean specialized; 1454 SpecialTreeVisitor() { 1455 this.specialized = false; 1456 } 1457 1458 @Override 1459 public void visitTree(JCTree tree) { /* no-op */ } 1460 1461 @Override 1462 public void visitVarDef(JCVariableDecl tree) { 1463 if ((tree.mods.flags & ENUM) != 0) { 1464 if (tree.init instanceof JCNewClass newClass && newClass.def != null) { 1465 specialized = true; 1466 } 1467 } 1468 } 1469 } 1470 1471 SpecialTreeVisitor sts = new SpecialTreeVisitor(); 1472 JCClassDecl cdef = (JCClassDecl) tree; 1473 for (JCTree defs: cdef.defs) { 1474 defs.accept(sts); 1475 if (sts.specialized) return allowSealed ? SEALED : 0; 1476 } 1477 return FINAL; 1478 } 1479 1480 /* ************************************************************************* 1481 * Type Validation 1482 **************************************************************************/ 1483 1484 /** Validate a type expression. That is, 1485 * check that all type arguments of a parametric type are within 1486 * their bounds. This must be done in a second phase after type attribution 1487 * since a class might have a subclass as type parameter bound. E.g: 1488 * 1489 * <pre>{@code 1490 * class B<A extends C> { ... } 1491 * class C extends B<C> { ... } 1492 * }</pre> 1493 * 1494 * and we can't make sure that the bound is already attributed because 1495 * of possible cycles. 1496 * 1497 * Visitor method: Validate a type expression, if it is not null, catching 1498 * and reporting any completion failures. 1499 */ 1500 void validate(JCTree tree, Env<AttrContext> env) { 1501 validate(tree, env, true); 1502 } 1503 void validate(JCTree tree, Env<AttrContext> env, boolean checkRaw) { 1504 new Validator(env).validateTree(tree, checkRaw, true); 1505 } 1506 1507 /** Visitor method: Validate a list of type expressions. 1508 */ 1509 void validate(List<? extends JCTree> trees, Env<AttrContext> env) { 1510 for (List<? extends JCTree> l = trees; l.nonEmpty(); l = l.tail) 1511 validate(l.head, env); 1512 } 1513 1514 /** A visitor class for type validation. 1515 */ 1516 class Validator extends JCTree.Visitor { 1517 1518 boolean checkRaw; 1519 boolean isOuter; 1520 Env<AttrContext> env; 1521 1522 Validator(Env<AttrContext> env) { 1523 this.env = env; 1524 } 1525 1526 @Override 1527 public void visitTypeArray(JCArrayTypeTree tree) { 1528 validateTree(tree.elemtype, checkRaw, isOuter); 1529 } 1530 1531 @Override 1532 public void visitTypeApply(JCTypeApply tree) { 1533 if (tree.type.hasTag(CLASS)) { 1534 List<JCExpression> args = tree.arguments; 1535 List<Type> forms = tree.type.tsym.type.getTypeArguments(); 1536 1537 Type incompatibleArg = firstIncompatibleTypeArg(tree.type); 1538 if (incompatibleArg != null) { 1539 for (JCTree arg : tree.arguments) { 1540 if (arg.type == incompatibleArg) { 1541 log.error(arg, Errors.NotWithinBounds(incompatibleArg, forms.head)); 1542 } 1543 forms = forms.tail; 1544 } 1545 } 1546 1547 forms = tree.type.tsym.type.getTypeArguments(); 1548 1549 boolean is_java_lang_Class = tree.type.tsym.flatName() == names.java_lang_Class; 1550 1551 // For matching pairs of actual argument types `a' and 1552 // formal type parameters with declared bound `b' ... 1553 while (args.nonEmpty() && forms.nonEmpty()) { 1554 validateTree(args.head, 1555 !(isOuter && is_java_lang_Class), 1556 false); 1557 args = args.tail; 1558 forms = forms.tail; 1559 } 1560 1561 // Check that this type is either fully parameterized, or 1562 // not parameterized at all. 1563 if (tree.type.getEnclosingType().isRaw()) 1564 log.error(tree.pos(), Errors.ImproperlyFormedTypeInnerRawParam); 1565 if (tree.clazz.hasTag(SELECT)) 1566 visitSelectInternal((JCFieldAccess)tree.clazz); 1567 } 1568 } 1569 1570 @Override 1571 public void visitTypeParameter(JCTypeParameter tree) { 1572 validateTrees(tree.bounds, true, isOuter); 1573 checkClassBounds(tree.pos(), tree.type); 1574 } 1575 1576 @Override 1577 public void visitWildcard(JCWildcard tree) { 1578 if (tree.inner != null) 1579 validateTree(tree.inner, true, isOuter); 1580 } 1581 1582 @Override 1583 public void visitSelect(JCFieldAccess tree) { 1584 if (tree.type.hasTag(CLASS)) { 1585 visitSelectInternal(tree); 1586 1587 // Check that this type is either fully parameterized, or 1588 // not parameterized at all. 1589 if (tree.selected.type.isParameterized() && tree.type.tsym.type.getTypeArguments().nonEmpty()) 1590 log.error(tree.pos(), Errors.ImproperlyFormedTypeParamMissing); 1591 } 1592 } 1593 1594 public void visitSelectInternal(JCFieldAccess tree) { 1595 if (tree.type.tsym.isStatic() && 1596 tree.selected.type.isParameterized()) { 1597 // The enclosing type is not a class, so we are 1598 // looking at a static member type. However, the 1599 // qualifying expression is parameterized. 1600 log.error(tree.pos(), Errors.CantSelectStaticClassFromParamType); 1601 } else { 1602 // otherwise validate the rest of the expression 1603 tree.selected.accept(this); 1604 } 1605 } 1606 1607 @Override 1608 public void visitAnnotatedType(JCAnnotatedType tree) { 1609 tree.underlyingType.accept(this); 1610 } 1611 1612 @Override 1613 public void visitTypeIdent(JCPrimitiveTypeTree that) { 1614 if (that.type.hasTag(TypeTag.VOID)) { 1615 log.error(that.pos(), Errors.VoidNotAllowedHere); 1616 } 1617 super.visitTypeIdent(that); 1618 } 1619 1620 /** Default visitor method: do nothing. 1621 */ 1622 @Override 1623 public void visitTree(JCTree tree) { 1624 } 1625 1626 public void validateTree(JCTree tree, boolean checkRaw, boolean isOuter) { 1627 if (tree != null) { 1628 boolean prevCheckRaw = this.checkRaw; 1629 this.checkRaw = checkRaw; 1630 this.isOuter = isOuter; 1631 1632 try { 1633 tree.accept(this); 1634 if (checkRaw) 1635 checkRaw(tree, env); 1636 } catch (CompletionFailure ex) { 1637 completionError(tree.pos(), ex); 1638 } finally { 1639 this.checkRaw = prevCheckRaw; 1640 } 1641 } 1642 } 1643 1644 public void validateTrees(List<? extends JCTree> trees, boolean checkRaw, boolean isOuter) { 1645 for (List<? extends JCTree> l = trees; l.nonEmpty(); l = l.tail) 1646 validateTree(l.head, checkRaw, isOuter); 1647 } 1648 } 1649 1650 void checkRaw(JCTree tree, Env<AttrContext> env) { 1651 if (lint.isEnabled(LintCategory.RAW) && 1652 tree.type.hasTag(CLASS) && 1653 !TreeInfo.isDiamond(tree) && 1654 !withinAnonConstr(env) && 1655 tree.type.isRaw()) { 1656 log.warning(LintCategory.RAW, 1657 tree.pos(), Warnings.RawClassUse(tree.type, tree.type.tsym.type)); 1658 } 1659 } 1660 //where 1661 private boolean withinAnonConstr(Env<AttrContext> env) { 1662 return env.enclClass.name.isEmpty() && 1663 env.enclMethod != null && env.enclMethod.name == names.init; 1664 } 1665 1666 /* ************************************************************************* 1667 * Exception checking 1668 **************************************************************************/ 1669 1670 /* The following methods treat classes as sets that contain 1671 * the class itself and all their subclasses 1672 */ 1673 1674 /** Is given type a subtype of some of the types in given list? 1675 */ 1676 boolean subset(Type t, List<Type> ts) { 1677 for (List<Type> l = ts; l.nonEmpty(); l = l.tail) 1678 if (types.isSubtype(t, l.head)) return true; 1679 return false; 1680 } 1681 1682 /** Is given type a subtype or supertype of 1683 * some of the types in given list? 1684 */ 1685 boolean intersects(Type t, List<Type> ts) { 1686 for (List<Type> l = ts; l.nonEmpty(); l = l.tail) 1687 if (types.isSubtype(t, l.head) || types.isSubtype(l.head, t)) return true; 1688 return false; 1689 } 1690 1691 /** Add type set to given type list, unless it is a subclass of some class 1692 * in the list. 1693 */ 1694 List<Type> incl(Type t, List<Type> ts) { 1695 return subset(t, ts) ? ts : excl(t, ts).prepend(t); 1696 } 1697 1698 /** Remove type set from type set list. 1699 */ 1700 List<Type> excl(Type t, List<Type> ts) { 1701 if (ts.isEmpty()) { 1702 return ts; 1703 } else { 1704 List<Type> ts1 = excl(t, ts.tail); 1705 if (types.isSubtype(ts.head, t)) return ts1; 1706 else if (ts1 == ts.tail) return ts; 1707 else return ts1.prepend(ts.head); 1708 } 1709 } 1710 1711 /** Form the union of two type set lists. 1712 */ 1713 List<Type> union(List<Type> ts1, List<Type> ts2) { 1714 List<Type> ts = ts1; 1715 for (List<Type> l = ts2; l.nonEmpty(); l = l.tail) 1716 ts = incl(l.head, ts); 1717 return ts; 1718 } 1719 1720 /** Form the difference of two type lists. 1721 */ 1722 List<Type> diff(List<Type> ts1, List<Type> ts2) { 1723 List<Type> ts = ts1; 1724 for (List<Type> l = ts2; l.nonEmpty(); l = l.tail) 1725 ts = excl(l.head, ts); 1726 return ts; 1727 } 1728 1729 /** Form the intersection of two type lists. 1730 */ 1731 public List<Type> intersect(List<Type> ts1, List<Type> ts2) { 1732 List<Type> ts = List.nil(); 1733 for (List<Type> l = ts1; l.nonEmpty(); l = l.tail) 1734 if (subset(l.head, ts2)) ts = incl(l.head, ts); 1735 for (List<Type> l = ts2; l.nonEmpty(); l = l.tail) 1736 if (subset(l.head, ts1)) ts = incl(l.head, ts); 1737 return ts; 1738 } 1739 1740 /** Is exc an exception symbol that need not be declared? 1741 */ 1742 boolean isUnchecked(ClassSymbol exc) { 1743 return 1744 exc.kind == ERR || 1745 exc.isSubClass(syms.errorType.tsym, types) || 1746 exc.isSubClass(syms.runtimeExceptionType.tsym, types); 1747 } 1748 1749 /** Is exc an exception type that need not be declared? 1750 */ 1751 boolean isUnchecked(Type exc) { 1752 return 1753 (exc.hasTag(TYPEVAR)) ? isUnchecked(types.supertype(exc)) : 1754 (exc.hasTag(CLASS)) ? isUnchecked((ClassSymbol)exc.tsym) : 1755 exc.hasTag(BOT); 1756 } 1757 1758 boolean isChecked(Type exc) { 1759 return !isUnchecked(exc); 1760 } 1761 1762 /** Same, but handling completion failures. 1763 */ 1764 boolean isUnchecked(DiagnosticPosition pos, Type exc) { 1765 try { 1766 return isUnchecked(exc); 1767 } catch (CompletionFailure ex) { 1768 completionError(pos, ex); 1769 return true; 1770 } 1771 } 1772 1773 /** Is exc handled by given exception list? 1774 */ 1775 boolean isHandled(Type exc, List<Type> handled) { 1776 return isUnchecked(exc) || subset(exc, handled); 1777 } 1778 1779 /** Return all exceptions in thrown list that are not in handled list. 1780 * @param thrown The list of thrown exceptions. 1781 * @param handled The list of handled exceptions. 1782 */ 1783 List<Type> unhandled(List<Type> thrown, List<Type> handled) { 1784 List<Type> unhandled = List.nil(); 1785 for (List<Type> l = thrown; l.nonEmpty(); l = l.tail) 1786 if (!isHandled(l.head, handled)) unhandled = unhandled.prepend(l.head); 1787 return unhandled; 1788 } 1789 1790 /* ************************************************************************* 1791 * Overriding/Implementation checking 1792 **************************************************************************/ 1793 1794 /** The level of access protection given by a flag set, 1795 * where PRIVATE is highest and PUBLIC is lowest. 1796 */ 1797 static int protection(long flags) { 1798 switch ((short)(flags & AccessFlags)) { 1799 case PRIVATE: return 3; 1800 case PROTECTED: return 1; 1801 default: 1802 case PUBLIC: return 0; 1803 case 0: return 2; 1804 } 1805 } 1806 1807 /** A customized "cannot override" error message. 1808 * @param m The overriding method. 1809 * @param other The overridden method. 1810 * @return An internationalized string. 1811 */ 1812 Fragment cannotOverride(MethodSymbol m, MethodSymbol other) { 1813 Symbol mloc = m.location(); 1814 Symbol oloc = other.location(); 1815 1816 if ((other.owner.flags() & INTERFACE) == 0) 1817 return Fragments.CantOverride(m, mloc, other, oloc); 1818 else if ((m.owner.flags() & INTERFACE) == 0) 1819 return Fragments.CantImplement(m, mloc, other, oloc); 1820 else 1821 return Fragments.ClashesWith(m, mloc, other, oloc); 1822 } 1823 1824 /** A customized "override" warning message. 1825 * @param m The overriding method. 1826 * @param other The overridden method. 1827 * @return An internationalized string. 1828 */ 1829 Fragment uncheckedOverrides(MethodSymbol m, MethodSymbol other) { 1830 Symbol mloc = m.location(); 1831 Symbol oloc = other.location(); 1832 1833 if ((other.owner.flags() & INTERFACE) == 0) 1834 return Fragments.UncheckedOverride(m, mloc, other, oloc); 1835 else if ((m.owner.flags() & INTERFACE) == 0) 1836 return Fragments.UncheckedImplement(m, mloc, other, oloc); 1837 else 1838 return Fragments.UncheckedClashWith(m, mloc, other, oloc); 1839 } 1840 1841 /** A customized "override" warning message. 1842 * @param m The overriding method. 1843 * @param other The overridden method. 1844 * @return An internationalized string. 1845 */ 1846 Fragment varargsOverrides(MethodSymbol m, MethodSymbol other) { 1847 Symbol mloc = m.location(); 1848 Symbol oloc = other.location(); 1849 1850 if ((other.owner.flags() & INTERFACE) == 0) 1851 return Fragments.VarargsOverride(m, mloc, other, oloc); 1852 else if ((m.owner.flags() & INTERFACE) == 0) 1853 return Fragments.VarargsImplement(m, mloc, other, oloc); 1854 else 1855 return Fragments.VarargsClashWith(m, mloc, other, oloc); 1856 } 1857 1858 /** Check that this method conforms with overridden method 'other'. 1859 * where `origin' is the class where checking started. 1860 * Complications: 1861 * (1) Do not check overriding of synthetic methods 1862 * (reason: they might be final). 1863 * todo: check whether this is still necessary. 1864 * (2) Admit the case where an interface proxy throws fewer exceptions 1865 * than the method it implements. Augment the proxy methods with the 1866 * undeclared exceptions in this case. 1867 * (3) When generics are enabled, admit the case where an interface proxy 1868 * has a result type 1869 * extended by the result type of the method it implements. 1870 * Change the proxies result type to the smaller type in this case. 1871 * 1872 * @param tree The tree from which positions 1873 * are extracted for errors. 1874 * @param m The overriding method. 1875 * @param other The overridden method. 1876 * @param origin The class of which the overriding method 1877 * is a member. 1878 */ 1879 void checkOverride(JCTree tree, 1880 MethodSymbol m, 1881 MethodSymbol other, 1882 ClassSymbol origin) { 1883 // Don't check overriding of synthetic methods or by bridge methods. 1884 if ((m.flags() & (SYNTHETIC|BRIDGE)) != 0 || (other.flags() & SYNTHETIC) != 0) { 1885 return; 1886 } 1887 1888 // Error if static method overrides instance method (JLS 8.4.8.2). 1889 if ((m.flags() & STATIC) != 0 && 1890 (other.flags() & STATIC) == 0) { 1891 log.error(TreeInfo.diagnosticPositionFor(m, tree), 1892 Errors.OverrideStatic(cannotOverride(m, other))); 1893 m.flags_field |= BAD_OVERRIDE; 1894 return; 1895 } 1896 1897 // Error if instance method overrides static or final 1898 // method (JLS 8.4.8.1). 1899 if ((other.flags() & FINAL) != 0 || 1900 (m.flags() & STATIC) == 0 && 1901 (other.flags() & STATIC) != 0) { 1902 log.error(TreeInfo.diagnosticPositionFor(m, tree), 1903 Errors.OverrideMeth(cannotOverride(m, other), 1904 asFlagSet(other.flags() & (FINAL | STATIC)))); 1905 m.flags_field |= BAD_OVERRIDE; 1906 return; 1907 } 1908 1909 if ((m.owner.flags() & ANNOTATION) != 0) { 1910 // handled in validateAnnotationMethod 1911 return; 1912 } 1913 1914 // Error if overriding method has weaker access (JLS 8.4.8.3). 1915 if (protection(m.flags()) > protection(other.flags())) { 1916 log.error(TreeInfo.diagnosticPositionFor(m, tree), 1917 (other.flags() & AccessFlags) == 0 ? 1918 Errors.OverrideWeakerAccess(cannotOverride(m, other), 1919 "package") : 1920 Errors.OverrideWeakerAccess(cannotOverride(m, other), 1921 asFlagSet(other.flags() & AccessFlags))); 1922 m.flags_field |= BAD_OVERRIDE; 1923 return; 1924 } 1925 1926 if (shouldCheckPreview(m, other, origin)) { 1927 checkPreview(tree.pos(), m, other); 1928 } 1929 1930 Type mt = types.memberType(origin.type, m); 1931 Type ot = types.memberType(origin.type, other); 1932 // Error if overriding result type is different 1933 // (or, in the case of generics mode, not a subtype) of 1934 // overridden result type. We have to rename any type parameters 1935 // before comparing types. 1936 List<Type> mtvars = mt.getTypeArguments(); 1937 List<Type> otvars = ot.getTypeArguments(); 1938 Type mtres = mt.getReturnType(); 1939 Type otres = types.subst(ot.getReturnType(), otvars, mtvars); 1940 1941 overrideWarner.clear(); 1942 boolean resultTypesOK = 1943 types.returnTypeSubstitutable(mt, ot, otres, overrideWarner); 1944 if (!resultTypesOK) { 1945 if ((m.flags() & STATIC) != 0 && (other.flags() & STATIC) != 0) { 1946 log.error(TreeInfo.diagnosticPositionFor(m, tree), 1947 Errors.OverrideIncompatibleRet(Fragments.CantHide(m, m.location(), other, 1948 other.location()), mtres, otres)); 1949 m.flags_field |= BAD_OVERRIDE; 1950 } else { 1951 log.error(TreeInfo.diagnosticPositionFor(m, tree), 1952 Errors.OverrideIncompatibleRet(cannotOverride(m, other), mtres, otres)); 1953 m.flags_field |= BAD_OVERRIDE; 1954 } 1955 return; 1956 } else if (overrideWarner.hasNonSilentLint(LintCategory.UNCHECKED)) { 1957 warnUnchecked(TreeInfo.diagnosticPositionFor(m, tree), 1958 Warnings.OverrideUncheckedRet(uncheckedOverrides(m, other), mtres, otres)); 1959 } 1960 1961 // Error if overriding method throws an exception not reported 1962 // by overridden method. 1963 List<Type> otthrown = types.subst(ot.getThrownTypes(), otvars, mtvars); 1964 List<Type> unhandledErased = unhandled(mt.getThrownTypes(), types.erasure(otthrown)); 1965 List<Type> unhandledUnerased = unhandled(mt.getThrownTypes(), otthrown); 1966 if (unhandledErased.nonEmpty()) { 1967 log.error(TreeInfo.diagnosticPositionFor(m, tree), 1968 Errors.OverrideMethDoesntThrow(cannotOverride(m, other), unhandledUnerased.head)); 1969 m.flags_field |= BAD_OVERRIDE; 1970 return; 1971 } 1972 else if (unhandledUnerased.nonEmpty()) { 1973 warnUnchecked(TreeInfo.diagnosticPositionFor(m, tree), 1974 Warnings.OverrideUncheckedThrown(cannotOverride(m, other), unhandledUnerased.head)); 1975 return; 1976 } 1977 1978 // Optional warning if varargs don't agree 1979 if ((((m.flags() ^ other.flags()) & Flags.VARARGS) != 0) 1980 && lint.isEnabled(LintCategory.OVERRIDES)) { 1981 log.warning(TreeInfo.diagnosticPositionFor(m, tree), 1982 ((m.flags() & Flags.VARARGS) != 0) 1983 ? Warnings.OverrideVarargsMissing(varargsOverrides(m, other)) 1984 : Warnings.OverrideVarargsExtra(varargsOverrides(m, other))); 1985 } 1986 1987 // Warn if instance method overrides bridge method (compiler spec ??) 1988 if ((other.flags() & BRIDGE) != 0) { 1989 log.warning(TreeInfo.diagnosticPositionFor(m, tree), 1990 Warnings.OverrideBridge(uncheckedOverrides(m, other))); 1991 } 1992 1993 // Warn if a deprecated method overridden by a non-deprecated one. 1994 if (!isDeprecatedOverrideIgnorable(other, origin)) { 1995 Lint prevLint = setLint(lint.augment(m)); 1996 try { 1997 checkDeprecated(() -> TreeInfo.diagnosticPositionFor(m, tree), m, other); 1998 } finally { 1999 setLint(prevLint); 2000 } 2001 } 2002 } 2003 // where 2004 private boolean shouldCheckPreview(MethodSymbol m, MethodSymbol other, ClassSymbol origin) { 2005 if (m.owner != origin || 2006 //performance - only do the expensive checks when the overridden method is a Preview API: 2007 (other.flags() & PREVIEW_API) == 0) { 2008 return false; 2009 } 2010 2011 for (Symbol s : types.membersClosure(origin.type, false).getSymbolsByName(m.name)) { 2012 if (m != s && m.overrides(s, origin, types, false)) { 2013 //only produce preview warnings or errors if "m" immediatelly overrides "other" 2014 //without intermediate overriding methods: 2015 return s == other; 2016 } 2017 } 2018 2019 return false; 2020 } 2021 private boolean isDeprecatedOverrideIgnorable(MethodSymbol m, ClassSymbol origin) { 2022 // If the method, m, is defined in an interface, then ignore the issue if the method 2023 // is only inherited via a supertype and also implemented in the supertype, 2024 // because in that case, we will rediscover the issue when examining the method 2025 // in the supertype. 2026 // If the method, m, is not defined in an interface, then the only time we need to 2027 // address the issue is when the method is the supertype implementation: any other 2028 // case, we will have dealt with when examining the supertype classes 2029 ClassSymbol mc = m.enclClass(); 2030 Type st = types.supertype(origin.type); 2031 if (!st.hasTag(CLASS)) 2032 return true; 2033 MethodSymbol stimpl = m.implementation((ClassSymbol)st.tsym, types, false); 2034 2035 if (mc != null && ((mc.flags() & INTERFACE) != 0)) { 2036 List<Type> intfs = types.interfaces(origin.type); 2037 return (intfs.contains(mc.type) ? false : (stimpl != null)); 2038 } 2039 else 2040 return (stimpl != m); 2041 } 2042 2043 2044 // used to check if there were any unchecked conversions 2045 Warner overrideWarner = new Warner(); 2046 2047 /** Check that a class does not inherit two concrete methods 2048 * with the same signature. 2049 * @param pos Position to be used for error reporting. 2050 * @param site The class type to be checked. 2051 */ 2052 public void checkCompatibleConcretes(DiagnosticPosition pos, Type site) { 2053 Type sup = types.supertype(site); 2054 if (!sup.hasTag(CLASS)) return; 2055 2056 for (Type t1 = sup; 2057 t1.hasTag(CLASS) && t1.tsym.type.isParameterized(); 2058 t1 = types.supertype(t1)) { 2059 for (Symbol s1 : t1.tsym.members().getSymbols(NON_RECURSIVE)) { 2060 if (s1.kind != MTH || 2061 (s1.flags() & (STATIC|SYNTHETIC|BRIDGE)) != 0 || 2062 !s1.isInheritedIn(site.tsym, types) || 2063 ((MethodSymbol)s1).implementation(site.tsym, 2064 types, 2065 true) != s1) 2066 continue; 2067 Type st1 = types.memberType(t1, s1); 2068 int s1ArgsLength = st1.getParameterTypes().length(); 2069 if (st1 == s1.type) continue; 2070 2071 for (Type t2 = sup; 2072 t2.hasTag(CLASS); 2073 t2 = types.supertype(t2)) { 2074 for (Symbol s2 : t2.tsym.members().getSymbolsByName(s1.name)) { 2075 if (s2 == s1 || 2076 s2.kind != MTH || 2077 (s2.flags() & (STATIC|SYNTHETIC|BRIDGE)) != 0 || 2078 s2.type.getParameterTypes().length() != s1ArgsLength || 2079 !s2.isInheritedIn(site.tsym, types) || 2080 ((MethodSymbol)s2).implementation(site.tsym, 2081 types, 2082 true) != s2) 2083 continue; 2084 Type st2 = types.memberType(t2, s2); 2085 if (types.overrideEquivalent(st1, st2)) 2086 log.error(pos, 2087 Errors.ConcreteInheritanceConflict(s1, t1, s2, t2, sup)); 2088 } 2089 } 2090 } 2091 } 2092 } 2093 2094 /** Check that classes (or interfaces) do not each define an abstract 2095 * method with same name and arguments but incompatible return types. 2096 * @param pos Position to be used for error reporting. 2097 * @param t1 The first argument type. 2098 * @param t2 The second argument type. 2099 */ 2100 public boolean checkCompatibleAbstracts(DiagnosticPosition pos, 2101 Type t1, 2102 Type t2, 2103 Type site) { 2104 if ((site.tsym.flags() & COMPOUND) != 0) { 2105 // special case for intersections: need to eliminate wildcards in supertypes 2106 t1 = types.capture(t1); 2107 t2 = types.capture(t2); 2108 } 2109 return firstIncompatibility(pos, t1, t2, site) == null; 2110 } 2111 2112 /** Return the first method which is defined with same args 2113 * but different return types in two given interfaces, or null if none 2114 * exists. 2115 * @param t1 The first type. 2116 * @param t2 The second type. 2117 * @param site The most derived type. 2118 * @return symbol from t2 that conflicts with one in t1. 2119 */ 2120 private Symbol firstIncompatibility(DiagnosticPosition pos, Type t1, Type t2, Type site) { 2121 Map<TypeSymbol,Type> interfaces1 = new HashMap<>(); 2122 closure(t1, interfaces1); 2123 Map<TypeSymbol,Type> interfaces2; 2124 if (t1 == t2) 2125 interfaces2 = interfaces1; 2126 else 2127 closure(t2, interfaces1, interfaces2 = new HashMap<>()); 2128 2129 for (Type t3 : interfaces1.values()) { 2130 for (Type t4 : interfaces2.values()) { 2131 Symbol s = firstDirectIncompatibility(pos, t3, t4, site); 2132 if (s != null) return s; 2133 } 2134 } 2135 return null; 2136 } 2137 2138 /** Compute all the supertypes of t, indexed by type symbol. */ 2139 private void closure(Type t, Map<TypeSymbol,Type> typeMap) { 2140 if (!t.hasTag(CLASS)) return; 2141 if (typeMap.put(t.tsym, t) == null) { 2142 closure(types.supertype(t), typeMap); 2143 for (Type i : types.interfaces(t)) 2144 closure(i, typeMap); 2145 } 2146 } 2147 2148 /** Compute all the supertypes of t, indexed by type symbol (except those in typesSkip). */ 2149 private void closure(Type t, Map<TypeSymbol,Type> typesSkip, Map<TypeSymbol,Type> typeMap) { 2150 if (!t.hasTag(CLASS)) return; 2151 if (typesSkip.get(t.tsym) != null) return; 2152 if (typeMap.put(t.tsym, t) == null) { 2153 closure(types.supertype(t), typesSkip, typeMap); 2154 for (Type i : types.interfaces(t)) 2155 closure(i, typesSkip, typeMap); 2156 } 2157 } 2158 2159 /** Return the first method in t2 that conflicts with a method from t1. */ 2160 private Symbol firstDirectIncompatibility(DiagnosticPosition pos, Type t1, Type t2, Type site) { 2161 for (Symbol s1 : t1.tsym.members().getSymbols(NON_RECURSIVE)) { 2162 Type st1 = null; 2163 if (s1.kind != MTH || !s1.isInheritedIn(site.tsym, types) || 2164 (s1.flags() & SYNTHETIC) != 0) continue; 2165 Symbol impl = ((MethodSymbol)s1).implementation(site.tsym, types, false); 2166 if (impl != null && (impl.flags() & ABSTRACT) == 0) continue; 2167 for (Symbol s2 : t2.tsym.members().getSymbolsByName(s1.name)) { 2168 if (s1 == s2) continue; 2169 if (s2.kind != MTH || !s2.isInheritedIn(site.tsym, types) || 2170 (s2.flags() & SYNTHETIC) != 0) continue; 2171 if (st1 == null) st1 = types.memberType(t1, s1); 2172 Type st2 = types.memberType(t2, s2); 2173 if (types.overrideEquivalent(st1, st2)) { 2174 List<Type> tvars1 = st1.getTypeArguments(); 2175 List<Type> tvars2 = st2.getTypeArguments(); 2176 Type rt1 = st1.getReturnType(); 2177 Type rt2 = types.subst(st2.getReturnType(), tvars2, tvars1); 2178 boolean compat = 2179 types.isSameType(rt1, rt2) || 2180 !rt1.isPrimitiveOrVoid() && 2181 !rt2.isPrimitiveOrVoid() && 2182 (types.covariantReturnType(rt1, rt2, types.noWarnings) || 2183 types.covariantReturnType(rt2, rt1, types.noWarnings)) || 2184 checkCommonOverriderIn(s1,s2,site); 2185 if (!compat) { 2186 if (types.isSameType(t1, t2)) { 2187 log.error(pos, Errors.IncompatibleDiffRetSameType(t1, 2188 s2.name, types.memberType(t2, s2).getParameterTypes())); 2189 } else { 2190 log.error(pos, Errors.TypesIncompatible(t1, t2, 2191 Fragments.IncompatibleDiffRet(s2.name, types.memberType(t2, s2).getParameterTypes()))); 2192 } 2193 return s2; 2194 } 2195 } else if (checkNameClash((ClassSymbol)site.tsym, s1, s2) && 2196 !checkCommonOverriderIn(s1, s2, site)) { 2197 log.error(pos, Errors.NameClashSameErasureNoOverride( 2198 s1.name, types.memberType(site, s1).asMethodType().getParameterTypes(), s1.location(), 2199 s2.name, types.memberType(site, s2).asMethodType().getParameterTypes(), s2.location())); 2200 return s2; 2201 } 2202 } 2203 } 2204 return null; 2205 } 2206 //WHERE 2207 boolean checkCommonOverriderIn(Symbol s1, Symbol s2, Type site) { 2208 Map<TypeSymbol,Type> supertypes = new HashMap<>(); 2209 Type st1 = types.memberType(site, s1); 2210 Type st2 = types.memberType(site, s2); 2211 closure(site, supertypes); 2212 for (Type t : supertypes.values()) { 2213 for (Symbol s3 : t.tsym.members().getSymbolsByName(s1.name)) { 2214 if (s3 == s1 || s3 == s2 || s3.kind != MTH || (s3.flags() & (BRIDGE|SYNTHETIC)) != 0) continue; 2215 Type st3 = types.memberType(site,s3); 2216 if (types.overrideEquivalent(st3, st1) && 2217 types.overrideEquivalent(st3, st2) && 2218 types.returnTypeSubstitutable(st3, st1) && 2219 types.returnTypeSubstitutable(st3, st2)) { 2220 return true; 2221 } 2222 } 2223 } 2224 return false; 2225 } 2226 2227 /** Check that a given method conforms with any method it overrides. 2228 * @param tree The tree from which positions are extracted 2229 * for errors. 2230 * @param m The overriding method. 2231 */ 2232 void checkOverride(Env<AttrContext> env, JCMethodDecl tree, MethodSymbol m) { 2233 ClassSymbol origin = (ClassSymbol)m.owner; 2234 if ((origin.flags() & ENUM) != 0 && names.finalize.equals(m.name)) { 2235 if (m.overrides(syms.enumFinalFinalize, origin, types, false)) { 2236 log.error(tree.pos(), Errors.EnumNoFinalize); 2237 return; 2238 } 2239 } 2240 if (allowValueClasses && origin.isValueClass() && names.finalize.equals(m.name)) { 2241 if (m.overrides(syms.objectFinalize, origin, types, false)) { 2242 log.warning(tree.pos(), Warnings.ValueFinalize); 2243 } 2244 } 2245 if (allowRecords && origin.isRecord()) { 2246 // let's find out if this is a user defined accessor in which case the @Override annotation is acceptable 2247 Optional<? extends RecordComponent> recordComponent = origin.getRecordComponents().stream() 2248 .filter(rc -> rc.accessor == tree.sym && (rc.accessor.flags_field & GENERATED_MEMBER) == 0).findFirst(); 2249 if (recordComponent.isPresent()) { 2250 return; 2251 } 2252 } 2253 2254 for (Type t = origin.type; t.hasTag(CLASS); 2255 t = types.supertype(t)) { 2256 if (t != origin.type) { 2257 checkOverride(tree, t, origin, m); 2258 } 2259 for (Type t2 : types.interfaces(t)) { 2260 checkOverride(tree, t2, origin, m); 2261 } 2262 } 2263 2264 final boolean explicitOverride = m.attribute(syms.overrideType.tsym) != null; 2265 // Check if this method must override a super method due to being annotated with @Override 2266 // or by virtue of being a member of a diamond inferred anonymous class. Latter case is to 2267 // be treated "as if as they were annotated" with @Override. 2268 boolean mustOverride = explicitOverride || 2269 (env.info.isAnonymousDiamond && !m.isConstructor() && !m.isPrivate()); 2270 if (mustOverride && !isOverrider(m)) { 2271 DiagnosticPosition pos = tree.pos(); 2272 for (JCAnnotation a : tree.getModifiers().annotations) { 2273 if (a.annotationType.type.tsym == syms.overrideType.tsym) { 2274 pos = a.pos(); 2275 break; 2276 } 2277 } 2278 log.error(pos, 2279 explicitOverride ? (m.isStatic() ? Errors.StaticMethodsCannotBeAnnotatedWithOverride : Errors.MethodDoesNotOverrideSuperclass) : 2280 Errors.AnonymousDiamondMethodDoesNotOverrideSuperclass(Fragments.DiamondAnonymousMethodsImplicitlyOverride)); 2281 } 2282 } 2283 2284 void checkOverride(JCTree tree, Type site, ClassSymbol origin, MethodSymbol m) { 2285 TypeSymbol c = site.tsym; 2286 for (Symbol sym : c.members().getSymbolsByName(m.name)) { 2287 if (m.overrides(sym, origin, types, false)) { 2288 if ((sym.flags() & ABSTRACT) == 0) { 2289 checkOverride(tree, m, (MethodSymbol)sym, origin); 2290 } 2291 } 2292 } 2293 } 2294 2295 private Predicate<Symbol> equalsHasCodeFilter = s -> MethodSymbol.implementation_filter.test(s) && 2296 (s.flags() & BAD_OVERRIDE) == 0; 2297 2298 public void checkClassOverrideEqualsAndHashIfNeeded(DiagnosticPosition pos, 2299 ClassSymbol someClass) { 2300 /* At present, annotations cannot possibly have a method that is override 2301 * equivalent with Object.equals(Object) but in any case the condition is 2302 * fine for completeness. 2303 */ 2304 if (someClass == (ClassSymbol)syms.objectType.tsym || 2305 someClass.isInterface() || someClass.isEnum() || 2306 (someClass.flags() & ANNOTATION) != 0 || 2307 (someClass.flags() & ABSTRACT) != 0) return; 2308 //anonymous inner classes implementing interfaces need especial treatment 2309 if (someClass.isAnonymous()) { 2310 List<Type> interfaces = types.interfaces(someClass.type); 2311 if (interfaces != null && !interfaces.isEmpty() && 2312 interfaces.head.tsym == syms.comparatorType.tsym) return; 2313 } 2314 checkClassOverrideEqualsAndHash(pos, someClass); 2315 } 2316 2317 private void checkClassOverrideEqualsAndHash(DiagnosticPosition pos, 2318 ClassSymbol someClass) { 2319 if (lint.isEnabled(LintCategory.OVERRIDES)) { 2320 MethodSymbol equalsAtObject = (MethodSymbol)syms.objectType 2321 .tsym.members().findFirst(names.equals); 2322 MethodSymbol hashCodeAtObject = (MethodSymbol)syms.objectType 2323 .tsym.members().findFirst(names.hashCode); 2324 MethodSymbol equalsImpl = types.implementation(equalsAtObject, 2325 someClass, false, equalsHasCodeFilter); 2326 boolean overridesEquals = equalsImpl != null && 2327 equalsImpl.owner == someClass; 2328 boolean overridesHashCode = types.implementation(hashCodeAtObject, 2329 someClass, false, equalsHasCodeFilter) != hashCodeAtObject; 2330 2331 if (overridesEquals && !overridesHashCode) { 2332 log.warning(LintCategory.OVERRIDES, pos, 2333 Warnings.OverrideEqualsButNotHashcode(someClass)); 2334 } 2335 } 2336 } 2337 2338 public void checkHasMain(DiagnosticPosition pos, ClassSymbol c) { 2339 boolean found = false; 2340 2341 for (Symbol sym : c.members().getSymbolsByName(names.main)) { 2342 if (sym.kind == MTH && (sym.flags() & PRIVATE) == 0) { 2343 MethodSymbol meth = (MethodSymbol)sym; 2344 if (!types.isSameType(meth.getReturnType(), syms.voidType)) { 2345 continue; 2346 } 2347 if (meth.params.isEmpty()) { 2348 found = true; 2349 break; 2350 } 2351 if (meth.params.size() != 1) { 2352 continue; 2353 } 2354 if (!types.isSameType(meth.params.head.type, types.makeArrayType(syms.stringType))) { 2355 continue; 2356 } 2357 2358 found = true; 2359 break; 2360 } 2361 } 2362 2363 if (!found) { 2364 log.error(pos, Errors.ImplicitClassDoesNotHaveMainMethod); 2365 } 2366 } 2367 2368 public void checkModuleName (JCModuleDecl tree) { 2369 Name moduleName = tree.sym.name; 2370 Assert.checkNonNull(moduleName); 2371 if (lint.isEnabled(LintCategory.MODULE)) { 2372 JCExpression qualId = tree.qualId; 2373 while (qualId != null) { 2374 Name componentName; 2375 DiagnosticPosition pos; 2376 switch (qualId.getTag()) { 2377 case SELECT: 2378 JCFieldAccess selectNode = ((JCFieldAccess) qualId); 2379 componentName = selectNode.name; 2380 pos = selectNode.pos(); 2381 qualId = selectNode.selected; 2382 break; 2383 case IDENT: 2384 componentName = ((JCIdent) qualId).name; 2385 pos = qualId.pos(); 2386 qualId = null; 2387 break; 2388 default: 2389 throw new AssertionError("Unexpected qualified identifier: " + qualId.toString()); 2390 } 2391 if (componentName != null) { 2392 String moduleNameComponentString = componentName.toString(); 2393 int nameLength = moduleNameComponentString.length(); 2394 if (nameLength > 0 && Character.isDigit(moduleNameComponentString.charAt(nameLength - 1))) { 2395 log.warning(Lint.LintCategory.MODULE, pos, Warnings.PoorChoiceForModuleName(componentName)); 2396 } 2397 } 2398 } 2399 } 2400 } 2401 2402 private boolean checkNameClash(ClassSymbol origin, Symbol s1, Symbol s2) { 2403 ClashFilter cf = new ClashFilter(origin.type); 2404 return (cf.test(s1) && 2405 cf.test(s2) && 2406 types.hasSameArgs(s1.erasure(types), s2.erasure(types))); 2407 } 2408 2409 2410 /** Check that all abstract members of given class have definitions. 2411 * @param pos Position to be used for error reporting. 2412 * @param c The class. 2413 */ 2414 void checkAllDefined(DiagnosticPosition pos, ClassSymbol c) { 2415 MethodSymbol undef = types.firstUnimplementedAbstract(c); 2416 if (undef != null) { 2417 MethodSymbol undef1 = 2418 new MethodSymbol(undef.flags(), undef.name, 2419 types.memberType(c.type, undef), undef.owner); 2420 log.error(pos, 2421 Errors.DoesNotOverrideAbstract(c, undef1, undef1.location())); 2422 } 2423 } 2424 2425 void checkNonCyclicDecl(JCClassDecl tree) { 2426 CycleChecker cc = new CycleChecker(); 2427 cc.scan(tree); 2428 if (!cc.errorFound && !cc.partialCheck) { 2429 tree.sym.flags_field |= ACYCLIC; 2430 } 2431 } 2432 2433 class CycleChecker extends TreeScanner { 2434 2435 Set<Symbol> seenClasses = new HashSet<>(); 2436 boolean errorFound = false; 2437 boolean partialCheck = false; 2438 2439 private void checkSymbol(DiagnosticPosition pos, Symbol sym) { 2440 if (sym != null && sym.kind == TYP) { 2441 Env<AttrContext> classEnv = enter.getEnv((TypeSymbol)sym); 2442 if (classEnv != null) { 2443 DiagnosticSource prevSource = log.currentSource(); 2444 try { 2445 log.useSource(classEnv.toplevel.sourcefile); 2446 scan(classEnv.tree); 2447 } 2448 finally { 2449 log.useSource(prevSource.getFile()); 2450 } 2451 } else if (sym.kind == TYP) { 2452 checkClass(pos, sym, List.nil()); 2453 } 2454 } else if (sym == null || sym.kind != PCK) { 2455 //not completed yet 2456 partialCheck = true; 2457 } 2458 } 2459 2460 @Override 2461 public void visitSelect(JCFieldAccess tree) { 2462 super.visitSelect(tree); 2463 checkSymbol(tree.pos(), tree.sym); 2464 } 2465 2466 @Override 2467 public void visitIdent(JCIdent tree) { 2468 checkSymbol(tree.pos(), tree.sym); 2469 } 2470 2471 @Override 2472 public void visitTypeApply(JCTypeApply tree) { 2473 scan(tree.clazz); 2474 } 2475 2476 @Override 2477 public void visitTypeArray(JCArrayTypeTree tree) { 2478 scan(tree.elemtype); 2479 } 2480 2481 @Override 2482 public void visitClassDef(JCClassDecl tree) { 2483 List<JCTree> supertypes = List.nil(); 2484 if (tree.getExtendsClause() != null) { 2485 supertypes = supertypes.prepend(tree.getExtendsClause()); 2486 } 2487 if (tree.getImplementsClause() != null) { 2488 for (JCTree intf : tree.getImplementsClause()) { 2489 supertypes = supertypes.prepend(intf); 2490 } 2491 } 2492 checkClass(tree.pos(), tree.sym, supertypes); 2493 } 2494 2495 void checkClass(DiagnosticPosition pos, Symbol c, List<JCTree> supertypes) { 2496 if ((c.flags_field & ACYCLIC) != 0) 2497 return; 2498 if (seenClasses.contains(c)) { 2499 errorFound = true; 2500 noteCyclic(pos, (ClassSymbol)c); 2501 } else if (!c.type.isErroneous()) { 2502 try { 2503 seenClasses.add(c); 2504 if (c.type.hasTag(CLASS)) { 2505 if (supertypes.nonEmpty()) { 2506 scan(supertypes); 2507 } 2508 else { 2509 ClassType ct = (ClassType)c.type; 2510 if (ct.supertype_field == null || 2511 ct.interfaces_field == null) { 2512 //not completed yet 2513 partialCheck = true; 2514 return; 2515 } 2516 checkSymbol(pos, ct.supertype_field.tsym); 2517 for (Type intf : ct.interfaces_field) { 2518 checkSymbol(pos, intf.tsym); 2519 } 2520 } 2521 if (c.owner.kind == TYP) { 2522 checkSymbol(pos, c.owner); 2523 } 2524 } 2525 } finally { 2526 seenClasses.remove(c); 2527 } 2528 } 2529 } 2530 } 2531 2532 /** Check for cyclic references. Issue an error if the 2533 * symbol of the type referred to has a LOCKED flag set. 2534 * 2535 * @param pos Position to be used for error reporting. 2536 * @param t The type referred to. 2537 */ 2538 void checkNonCyclic(DiagnosticPosition pos, Type t) { 2539 checkNonCyclicInternal(pos, t); 2540 } 2541 2542 2543 void checkNonCyclic(DiagnosticPosition pos, TypeVar t) { 2544 checkNonCyclic1(pos, t, List.nil()); 2545 } 2546 2547 private void checkNonCyclic1(DiagnosticPosition pos, Type t, List<TypeVar> seen) { 2548 final TypeVar tv; 2549 if (t.hasTag(TYPEVAR) && (t.tsym.flags() & UNATTRIBUTED) != 0) 2550 return; 2551 if (seen.contains(t)) { 2552 tv = (TypeVar)t; 2553 tv.setUpperBound(types.createErrorType(t)); 2554 log.error(pos, Errors.CyclicInheritance(t)); 2555 } else if (t.hasTag(TYPEVAR)) { 2556 tv = (TypeVar)t; 2557 seen = seen.prepend(tv); 2558 for (Type b : types.getBounds(tv)) 2559 checkNonCyclic1(pos, b, seen); 2560 } 2561 } 2562 2563 /** Check for cyclic references. Issue an error if the 2564 * symbol of the type referred to has a LOCKED flag set. 2565 * 2566 * @param pos Position to be used for error reporting. 2567 * @param t The type referred to. 2568 * @return True if the check completed on all attributed classes 2569 */ 2570 private boolean checkNonCyclicInternal(DiagnosticPosition pos, Type t) { 2571 boolean complete = true; // was the check complete? 2572 //- System.err.println("checkNonCyclicInternal("+t+");");//DEBUG 2573 Symbol c = t.tsym; 2574 if ((c.flags_field & ACYCLIC) != 0) return true; 2575 2576 if ((c.flags_field & LOCKED) != 0) { 2577 noteCyclic(pos, (ClassSymbol)c); 2578 } else if (!c.type.isErroneous()) { 2579 try { 2580 c.flags_field |= LOCKED; 2581 if (c.type.hasTag(CLASS)) { 2582 ClassType clazz = (ClassType)c.type; 2583 if (clazz.interfaces_field != null) 2584 for (List<Type> l=clazz.interfaces_field; l.nonEmpty(); l=l.tail) 2585 complete &= checkNonCyclicInternal(pos, l.head); 2586 if (clazz.supertype_field != null) { 2587 Type st = clazz.supertype_field; 2588 if (st != null && st.hasTag(CLASS)) 2589 complete &= checkNonCyclicInternal(pos, st); 2590 } 2591 if (c.owner.kind == TYP) 2592 complete &= checkNonCyclicInternal(pos, c.owner.type); 2593 } 2594 } finally { 2595 c.flags_field &= ~LOCKED; 2596 } 2597 } 2598 if (complete) 2599 complete = ((c.flags_field & UNATTRIBUTED) == 0) && c.isCompleted(); 2600 if (complete) c.flags_field |= ACYCLIC; 2601 return complete; 2602 } 2603 2604 /** Note that we found an inheritance cycle. */ 2605 private void noteCyclic(DiagnosticPosition pos, ClassSymbol c) { 2606 log.error(pos, Errors.CyclicInheritance(c)); 2607 for (List<Type> l=types.interfaces(c.type); l.nonEmpty(); l=l.tail) 2608 l.head = types.createErrorType((ClassSymbol)l.head.tsym, Type.noType); 2609 Type st = types.supertype(c.type); 2610 if (st.hasTag(CLASS)) 2611 ((ClassType)c.type).supertype_field = types.createErrorType((ClassSymbol)st.tsym, Type.noType); 2612 c.type = types.createErrorType(c, c.type); 2613 c.flags_field |= ACYCLIC; 2614 } 2615 2616 /** Check that all methods which implement some 2617 * method conform to the method they implement. 2618 * @param tree The class definition whose members are checked. 2619 */ 2620 void checkImplementations(JCClassDecl tree) { 2621 checkImplementations(tree, tree.sym, tree.sym); 2622 } 2623 //where 2624 /** Check that all methods which implement some 2625 * method in `ic' conform to the method they implement. 2626 */ 2627 void checkImplementations(JCTree tree, ClassSymbol origin, ClassSymbol ic) { 2628 for (List<Type> l = types.closure(ic.type); l.nonEmpty(); l = l.tail) { 2629 ClassSymbol lc = (ClassSymbol)l.head.tsym; 2630 if ((lc.flags() & ABSTRACT) != 0) { 2631 for (Symbol sym : lc.members().getSymbols(NON_RECURSIVE)) { 2632 if (sym.kind == MTH && 2633 (sym.flags() & (STATIC|ABSTRACT)) == ABSTRACT) { 2634 MethodSymbol absmeth = (MethodSymbol)sym; 2635 MethodSymbol implmeth = absmeth.implementation(origin, types, false); 2636 if (implmeth != null && implmeth != absmeth && 2637 (implmeth.owner.flags() & INTERFACE) == 2638 (origin.flags() & INTERFACE)) { 2639 // don't check if implmeth is in a class, yet 2640 // origin is an interface. This case arises only 2641 // if implmeth is declared in Object. The reason is 2642 // that interfaces really don't inherit from 2643 // Object it's just that the compiler represents 2644 // things that way. 2645 checkOverride(tree, implmeth, absmeth, origin); 2646 } 2647 } 2648 } 2649 } 2650 } 2651 } 2652 2653 /** Check that all abstract methods implemented by a class are 2654 * mutually compatible. 2655 * @param pos Position to be used for error reporting. 2656 * @param c The class whose interfaces are checked. 2657 */ 2658 void checkCompatibleSupertypes(DiagnosticPosition pos, Type c) { 2659 List<Type> supertypes = types.interfaces(c); 2660 Type supertype = types.supertype(c); 2661 if (supertype.hasTag(CLASS) && 2662 (supertype.tsym.flags() & ABSTRACT) != 0) 2663 supertypes = supertypes.prepend(supertype); 2664 for (List<Type> l = supertypes; l.nonEmpty(); l = l.tail) { 2665 if (!l.head.getTypeArguments().isEmpty() && 2666 !checkCompatibleAbstracts(pos, l.head, l.head, c)) 2667 return; 2668 for (List<Type> m = supertypes; m != l; m = m.tail) 2669 if (!checkCompatibleAbstracts(pos, l.head, m.head, c)) 2670 return; 2671 } 2672 checkCompatibleConcretes(pos, c); 2673 2674 Type identitySuper = null; 2675 for (Type t : types.closure(c)) { 2676 if (t != c) { 2677 if (t.isIdentityClass() && (t.tsym.flags() & VALUE_BASED) == 0) 2678 identitySuper = t; 2679 if (c.isValueClass() && identitySuper != null && identitySuper.tsym != syms.objectType.tsym) { // Object is special 2680 log.error(pos, Errors.ValueTypeHasIdentitySuperType(c, identitySuper)); 2681 break; 2682 } 2683 } 2684 } 2685 } 2686 2687 /** Check that all non-override equivalent methods accessible from 'site' 2688 * are mutually compatible (JLS 8.4.8/9.4.1). 2689 * 2690 * @param pos Position to be used for error reporting. 2691 * @param site The class whose methods are checked. 2692 * @param sym The method symbol to be checked. 2693 */ 2694 void checkOverrideClashes(DiagnosticPosition pos, Type site, MethodSymbol sym) { 2695 ClashFilter cf = new ClashFilter(site); 2696 //for each method m1 that is overridden (directly or indirectly) 2697 //by method 'sym' in 'site'... 2698 2699 ArrayList<Symbol> symbolsByName = new ArrayList<>(); 2700 types.membersClosure(site, false).getSymbolsByName(sym.name, cf).forEach(symbolsByName::add); 2701 for (Symbol m1 : symbolsByName) { 2702 if (!sym.overrides(m1, site.tsym, types, false)) { 2703 continue; 2704 } 2705 2706 //...check each method m2 that is a member of 'site' 2707 for (Symbol m2 : symbolsByName) { 2708 if (m2 == m1) continue; 2709 //if (i) the signature of 'sym' is not a subsignature of m1 (seen as 2710 //a member of 'site') and (ii) m1 has the same erasure as m2, issue an error 2711 if (!types.isSubSignature(sym.type, types.memberType(site, m2)) && 2712 types.hasSameArgs(m2.erasure(types), m1.erasure(types))) { 2713 sym.flags_field |= CLASH; 2714 if (m1 == sym) { 2715 log.error(pos, Errors.NameClashSameErasureNoOverride( 2716 m1.name, types.memberType(site, m1).asMethodType().getParameterTypes(), m1.location(), 2717 m2.name, types.memberType(site, m2).asMethodType().getParameterTypes(), m2.location())); 2718 } else { 2719 ClassType ct = (ClassType)site; 2720 String kind = ct.isInterface() ? "interface" : "class"; 2721 log.error(pos, Errors.NameClashSameErasureNoOverride1( 2722 kind, 2723 ct.tsym.name, 2724 m1.name, 2725 types.memberType(site, m1).asMethodType().getParameterTypes(), 2726 m1.location(), 2727 m2.name, 2728 types.memberType(site, m2).asMethodType().getParameterTypes(), 2729 m2.location())); 2730 } 2731 return; 2732 } 2733 } 2734 } 2735 } 2736 2737 /** Check that all static methods accessible from 'site' are 2738 * mutually compatible (JLS 8.4.8). 2739 * 2740 * @param pos Position to be used for error reporting. 2741 * @param site The class whose methods are checked. 2742 * @param sym The method symbol to be checked. 2743 */ 2744 void checkHideClashes(DiagnosticPosition pos, Type site, MethodSymbol sym) { 2745 ClashFilter cf = new ClashFilter(site); 2746 //for each method m1 that is a member of 'site'... 2747 for (Symbol s : types.membersClosure(site, true).getSymbolsByName(sym.name, cf)) { 2748 //if (i) the signature of 'sym' is not a subsignature of m1 (seen as 2749 //a member of 'site') and (ii) 'sym' has the same erasure as m1, issue an error 2750 if (!types.isSubSignature(sym.type, types.memberType(site, s))) { 2751 if (types.hasSameArgs(s.erasure(types), sym.erasure(types))) { 2752 log.error(pos, 2753 Errors.NameClashSameErasureNoHide(sym, sym.location(), s, s.location())); 2754 return; 2755 } 2756 } 2757 } 2758 } 2759 2760 //where 2761 private class ClashFilter implements Predicate<Symbol> { 2762 2763 Type site; 2764 2765 ClashFilter(Type site) { 2766 this.site = site; 2767 } 2768 2769 boolean shouldSkip(Symbol s) { 2770 return (s.flags() & CLASH) != 0 && 2771 s.owner == site.tsym; 2772 } 2773 2774 @Override 2775 public boolean test(Symbol s) { 2776 return s.kind == MTH && 2777 (s.flags() & SYNTHETIC) == 0 && 2778 !shouldSkip(s) && 2779 s.isInheritedIn(site.tsym, types) && 2780 !s.isConstructor(); 2781 } 2782 } 2783 2784 void checkDefaultMethodClashes(DiagnosticPosition pos, Type site) { 2785 DefaultMethodClashFilter dcf = new DefaultMethodClashFilter(site); 2786 for (Symbol m : types.membersClosure(site, false).getSymbols(dcf)) { 2787 Assert.check(m.kind == MTH); 2788 List<MethodSymbol> prov = types.interfaceCandidates(site, (MethodSymbol)m); 2789 if (prov.size() > 1) { 2790 ListBuffer<Symbol> abstracts = new ListBuffer<>(); 2791 ListBuffer<Symbol> defaults = new ListBuffer<>(); 2792 for (MethodSymbol provSym : prov) { 2793 if ((provSym.flags() & DEFAULT) != 0) { 2794 defaults = defaults.append(provSym); 2795 } else if ((provSym.flags() & ABSTRACT) != 0) { 2796 abstracts = abstracts.append(provSym); 2797 } 2798 if (defaults.nonEmpty() && defaults.size() + abstracts.size() >= 2) { 2799 //strong semantics - issue an error if two sibling interfaces 2800 //have two override-equivalent defaults - or if one is abstract 2801 //and the other is default 2802 Fragment diagKey; 2803 Symbol s1 = defaults.first(); 2804 Symbol s2; 2805 if (defaults.size() > 1) { 2806 s2 = defaults.toList().tail.head; 2807 diagKey = Fragments.IncompatibleUnrelatedDefaults(Kinds.kindName(site.tsym), site, 2808 m.name, types.memberType(site, m).getParameterTypes(), 2809 s1.location(), s2.location()); 2810 2811 } else { 2812 s2 = abstracts.first(); 2813 diagKey = Fragments.IncompatibleAbstractDefault(Kinds.kindName(site.tsym), site, 2814 m.name, types.memberType(site, m).getParameterTypes(), 2815 s1.location(), s2.location()); 2816 } 2817 log.error(pos, Errors.TypesIncompatible(s1.location().type, s2.location().type, diagKey)); 2818 break; 2819 } 2820 } 2821 } 2822 } 2823 } 2824 2825 //where 2826 private class DefaultMethodClashFilter implements Predicate<Symbol> { 2827 2828 Type site; 2829 2830 DefaultMethodClashFilter(Type site) { 2831 this.site = site; 2832 } 2833 2834 @Override 2835 public boolean test(Symbol s) { 2836 return s.kind == MTH && 2837 (s.flags() & DEFAULT) != 0 && 2838 s.isInheritedIn(site.tsym, types) && 2839 !s.isConstructor(); 2840 } 2841 } 2842 2843 /** Report warnings for potentially ambiguous method declarations in the given site. */ 2844 void checkPotentiallyAmbiguousOverloads(JCClassDecl tree, Type site) { 2845 2846 // Skip if warning not enabled 2847 if (!lint.isEnabled(LintCategory.OVERLOADS)) 2848 return; 2849 2850 // Gather all of site's methods, including overridden methods, grouped by name (except Object methods) 2851 List<java.util.List<MethodSymbol>> methodGroups = methodsGroupedByName(site, 2852 new PotentiallyAmbiguousFilter(site), ArrayList::new); 2853 2854 // Build the predicate that determines if site is responsible for an ambiguity 2855 BiPredicate<MethodSymbol, MethodSymbol> responsible = buildResponsiblePredicate(site, methodGroups); 2856 2857 // Now remove overridden methods from each group, leaving only site's actual members 2858 methodGroups.forEach(list -> removePreempted(list, (m1, m2) -> m1.overrides(m2, site.tsym, types, false))); 2859 2860 // Allow site's own declared methods (only) to apply @SuppressWarnings("overloads") 2861 methodGroups.forEach(list -> list.removeIf( 2862 m -> m.owner == site.tsym && !lint.augment(m).isEnabled(LintCategory.OVERLOADS))); 2863 2864 // Warn about ambiguous overload method pairs for which site is responsible 2865 methodGroups.forEach(list -> compareAndRemove(list, (m1, m2) -> { 2866 2867 // See if this is an ambiguous overload for which "site" is responsible 2868 if (!potentiallyAmbiguousOverload(site, m1, m2) || !responsible.test(m1, m2)) 2869 return 0; 2870 2871 // Locate the warning at one of the methods, if possible 2872 DiagnosticPosition pos = 2873 m1.owner == site.tsym ? TreeInfo.diagnosticPositionFor(m1, tree) : 2874 m2.owner == site.tsym ? TreeInfo.diagnosticPositionFor(m2, tree) : 2875 tree.pos(); 2876 2877 // Log the warning 2878 log.warning(LintCategory.OVERLOADS, pos, 2879 Warnings.PotentiallyAmbiguousOverload( 2880 m1.asMemberOf(site, types), m1.location(), 2881 m2.asMemberOf(site, types), m2.location())); 2882 2883 // Don't warn again for either of these two methods 2884 return FIRST | SECOND; 2885 })); 2886 } 2887 2888 /** Build a predicate that determines, given two methods that are members of the given class, 2889 * whether the class should be held "responsible" if the methods are potentially ambiguous. 2890 * 2891 * Sometimes ambiguous methods are unavoidable because they're inherited from a supertype. 2892 * For example, any subtype of Spliterator.OfInt will have ambiguities for both 2893 * forEachRemaining() and tryAdvance() (in both cases the overloads are IntConsumer and 2894 * Consumer<? super Integer>). So we only want to "blame" a class when that class is 2895 * itself responsible for creating the ambiguity. We declare that a class C is "responsible" 2896 * for the ambiguity between two methods m1 and m2 if there is no direct supertype T of C 2897 * such that m1 and m2, or some overrides thereof, both exist in T and are ambiguous in T. 2898 * As an optimization, we first check if either method is declared in C and does not override 2899 * any other methods; in this case the class is definitely responsible. 2900 */ 2901 BiPredicate<MethodSymbol, MethodSymbol> buildResponsiblePredicate(Type site, 2902 List<? extends Collection<MethodSymbol>> methodGroups) { 2903 2904 // Define the "overrides" predicate 2905 BiPredicate<MethodSymbol, MethodSymbol> overrides = (m1, m2) -> m1.overrides(m2, site.tsym, types, false); 2906 2907 // Map each method declared in site to a list of the supertype method(s) it directly overrides 2908 HashMap<MethodSymbol, ArrayList<MethodSymbol>> overriddenMethodsMap = new HashMap<>(); 2909 methodGroups.forEach(list -> { 2910 for (MethodSymbol m : list) { 2911 2912 // Skip methods not declared in site 2913 if (m.owner != site.tsym) 2914 continue; 2915 2916 // Gather all supertype methods overridden by m, directly or indirectly 2917 ArrayList<MethodSymbol> overriddenMethods = list.stream() 2918 .filter(m2 -> m2 != m && overrides.test(m, m2)) 2919 .collect(Collectors.toCollection(ArrayList::new)); 2920 2921 // Eliminate non-direct overrides 2922 removePreempted(overriddenMethods, overrides); 2923 2924 // Add to map 2925 overriddenMethodsMap.put(m, overriddenMethods); 2926 } 2927 }); 2928 2929 // Build the predicate 2930 return (m1, m2) -> { 2931 2932 // Get corresponding supertype methods (if declared in site) 2933 java.util.List<MethodSymbol> overriddenMethods1 = overriddenMethodsMap.get(m1); 2934 java.util.List<MethodSymbol> overriddenMethods2 = overriddenMethodsMap.get(m2); 2935 2936 // Quick check for the case where a method was added by site itself 2937 if (overriddenMethods1 != null && overriddenMethods1.isEmpty()) 2938 return true; 2939 if (overriddenMethods2 != null && overriddenMethods2.isEmpty()) 2940 return true; 2941 2942 // Get each method's corresponding method(s) from supertypes of site 2943 java.util.List<MethodSymbol> supertypeMethods1 = overriddenMethods1 != null ? 2944 overriddenMethods1 : Collections.singletonList(m1); 2945 java.util.List<MethodSymbol> supertypeMethods2 = overriddenMethods2 != null ? 2946 overriddenMethods2 : Collections.singletonList(m2); 2947 2948 // See if we can blame some direct supertype instead 2949 return types.directSupertypes(site).stream() 2950 .filter(stype -> stype != syms.objectType) 2951 .map(stype -> stype.tsym.type) // view supertype in its original form 2952 .noneMatch(stype -> { 2953 for (MethodSymbol sm1 : supertypeMethods1) { 2954 if (!types.isSubtype(types.erasure(stype), types.erasure(sm1.owner.type))) 2955 continue; 2956 for (MethodSymbol sm2 : supertypeMethods2) { 2957 if (!types.isSubtype(types.erasure(stype), types.erasure(sm2.owner.type))) 2958 continue; 2959 if (potentiallyAmbiguousOverload(stype, sm1, sm2)) 2960 return true; 2961 } 2962 } 2963 return false; 2964 }); 2965 }; 2966 } 2967 2968 /** Gather all of site's methods, including overridden methods, grouped and sorted by name, 2969 * after applying the given filter. 2970 */ 2971 <C extends Collection<MethodSymbol>> List<C> methodsGroupedByName(Type site, 2972 Predicate<Symbol> filter, Supplier<? extends C> groupMaker) { 2973 Iterable<Symbol> symbols = types.membersClosure(site, false).getSymbols(filter, RECURSIVE); 2974 return StreamSupport.stream(symbols.spliterator(), false) 2975 .map(MethodSymbol.class::cast) 2976 .collect(Collectors.groupingBy(m -> m.name, Collectors.toCollection(groupMaker))) 2977 .entrySet() 2978 .stream() 2979 .sorted(Comparator.comparing(e -> e.getKey().toString())) 2980 .map(Map.Entry::getValue) 2981 .collect(List.collector()); 2982 } 2983 2984 /** Compare elements in a list pair-wise in order to remove some of them. 2985 * @param list mutable list of items 2986 * @param comparer returns flag bit(s) to remove FIRST and/or SECOND 2987 */ 2988 <T> void compareAndRemove(java.util.List<T> list, ToIntBiFunction<? super T, ? super T> comparer) { 2989 for (int index1 = 0; index1 < list.size() - 1; index1++) { 2990 T item1 = list.get(index1); 2991 for (int index2 = index1 + 1; index2 < list.size(); index2++) { 2992 T item2 = list.get(index2); 2993 int flags = comparer.applyAsInt(item1, item2); 2994 if ((flags & SECOND) != 0) 2995 list.remove(index2--); // remove item2 2996 if ((flags & FIRST) != 0) { 2997 list.remove(index1--); // remove item1 2998 break; 2999 } 3000 } 3001 } 3002 } 3003 3004 /** Remove elements in a list that are preempted by some other element in the list. 3005 * @param list mutable list of items 3006 * @param preempts decides if one item preempts another, causing the second one to be removed 3007 */ 3008 <T> void removePreempted(java.util.List<T> list, BiPredicate<? super T, ? super T> preempts) { 3009 compareAndRemove(list, (item1, item2) -> { 3010 int flags = 0; 3011 if (preempts.test(item1, item2)) 3012 flags |= SECOND; 3013 if (preempts.test(item2, item1)) 3014 flags |= FIRST; 3015 return flags; 3016 }); 3017 } 3018 3019 /** Filters method candidates for the "potentially ambiguous method" check */ 3020 class PotentiallyAmbiguousFilter extends ClashFilter { 3021 3022 PotentiallyAmbiguousFilter(Type site) { 3023 super(site); 3024 } 3025 3026 @Override 3027 boolean shouldSkip(Symbol s) { 3028 return s.owner.type.tsym == syms.objectType.tsym || super.shouldSkip(s); 3029 } 3030 } 3031 3032 /** 3033 * Report warnings for potentially ambiguous method declarations. Two declarations 3034 * are potentially ambiguous if they feature two unrelated functional interface 3035 * in same argument position (in which case, a call site passing an implicit 3036 * lambda would be ambiguous). This assumes they already have the same name. 3037 */ 3038 boolean potentiallyAmbiguousOverload(Type site, MethodSymbol msym1, MethodSymbol msym2) { 3039 Assert.check(msym1.name == msym2.name); 3040 if (msym1 == msym2) 3041 return false; 3042 Type mt1 = types.memberType(site, msym1); 3043 Type mt2 = types.memberType(site, msym2); 3044 //if both generic methods, adjust type variables 3045 if (mt1.hasTag(FORALL) && mt2.hasTag(FORALL) && 3046 types.hasSameBounds((ForAll)mt1, (ForAll)mt2)) { 3047 mt2 = types.subst(mt2, ((ForAll)mt2).tvars, ((ForAll)mt1).tvars); 3048 } 3049 //expand varargs methods if needed 3050 int maxLength = Math.max(mt1.getParameterTypes().length(), mt2.getParameterTypes().length()); 3051 List<Type> args1 = rs.adjustArgs(mt1.getParameterTypes(), msym1, maxLength, true); 3052 List<Type> args2 = rs.adjustArgs(mt2.getParameterTypes(), msym2, maxLength, true); 3053 //if arities don't match, exit 3054 if (args1.length() != args2.length()) 3055 return false; 3056 boolean potentiallyAmbiguous = false; 3057 while (args1.nonEmpty() && args2.nonEmpty()) { 3058 Type s = args1.head; 3059 Type t = args2.head; 3060 if (!types.isSubtype(t, s) && !types.isSubtype(s, t)) { 3061 if (types.isFunctionalInterface(s) && types.isFunctionalInterface(t) && 3062 types.findDescriptorType(s).getParameterTypes().length() > 0 && 3063 types.findDescriptorType(s).getParameterTypes().length() == 3064 types.findDescriptorType(t).getParameterTypes().length()) { 3065 potentiallyAmbiguous = true; 3066 } else { 3067 return false; 3068 } 3069 } 3070 args1 = args1.tail; 3071 args2 = args2.tail; 3072 } 3073 return potentiallyAmbiguous; 3074 } 3075 3076 void checkAccessFromSerializableElement(final JCTree tree, boolean isLambda) { 3077 if (warnOnAnyAccessToMembers || 3078 (lint.isEnabled(LintCategory.SERIAL) && 3079 !lint.isSuppressed(LintCategory.SERIAL) && 3080 isLambda)) { 3081 Symbol sym = TreeInfo.symbol(tree); 3082 if (!sym.kind.matches(KindSelector.VAL_MTH)) { 3083 return; 3084 } 3085 3086 if (sym.kind == VAR) { 3087 if ((sym.flags() & PARAMETER) != 0 || 3088 sym.isDirectlyOrIndirectlyLocal() || 3089 sym.name == names._this || 3090 sym.name == names._super) { 3091 return; 3092 } 3093 } 3094 3095 if (!types.isSubtype(sym.owner.type, syms.serializableType) && 3096 isEffectivelyNonPublic(sym)) { 3097 if (isLambda) { 3098 if (belongsToRestrictedPackage(sym)) { 3099 log.warning(LintCategory.SERIAL, tree.pos(), 3100 Warnings.AccessToMemberFromSerializableLambda(sym)); 3101 } 3102 } else { 3103 log.warning(tree.pos(), 3104 Warnings.AccessToMemberFromSerializableElement(sym)); 3105 } 3106 } 3107 } 3108 } 3109 3110 private boolean isEffectivelyNonPublic(Symbol sym) { 3111 if (sym.packge() == syms.rootPackage) { 3112 return false; 3113 } 3114 3115 while (sym.kind != PCK) { 3116 if ((sym.flags() & PUBLIC) == 0) { 3117 return true; 3118 } 3119 sym = sym.owner; 3120 } 3121 return false; 3122 } 3123 3124 private boolean belongsToRestrictedPackage(Symbol sym) { 3125 String fullName = sym.packge().fullname.toString(); 3126 return fullName.startsWith("java.") || 3127 fullName.startsWith("javax.") || 3128 fullName.startsWith("sun.") || 3129 fullName.contains(".internal."); 3130 } 3131 3132 /** Check that class c does not implement directly or indirectly 3133 * the same parameterized interface with two different argument lists. 3134 * @param pos Position to be used for error reporting. 3135 * @param type The type whose interfaces are checked. 3136 */ 3137 void checkClassBounds(DiagnosticPosition pos, Type type) { 3138 checkClassBounds(pos, new HashMap<TypeSymbol,Type>(), type); 3139 } 3140 //where 3141 /** Enter all interfaces of type `type' into the hash table `seensofar' 3142 * with their class symbol as key and their type as value. Make 3143 * sure no class is entered with two different types. 3144 */ 3145 void checkClassBounds(DiagnosticPosition pos, 3146 Map<TypeSymbol,Type> seensofar, 3147 Type type) { 3148 if (type.isErroneous()) return; 3149 for (List<Type> l = types.interfaces(type); l.nonEmpty(); l = l.tail) { 3150 Type it = l.head; 3151 if (type.hasTag(CLASS) && !it.hasTag(CLASS)) continue; // JLS 8.1.5 3152 3153 Type oldit = seensofar.put(it.tsym, it); 3154 if (oldit != null) { 3155 List<Type> oldparams = oldit.allparams(); 3156 List<Type> newparams = it.allparams(); 3157 if (!types.containsTypeEquivalent(oldparams, newparams)) 3158 log.error(pos, 3159 Errors.CantInheritDiffArg(it.tsym, 3160 Type.toString(oldparams), 3161 Type.toString(newparams))); 3162 } 3163 checkClassBounds(pos, seensofar, it); 3164 } 3165 Type st = types.supertype(type); 3166 if (type.hasTag(CLASS) && !st.hasTag(CLASS)) return; // JLS 8.1.4 3167 if (st != Type.noType) checkClassBounds(pos, seensofar, st); 3168 } 3169 3170 /** Enter interface into into set. 3171 * If it existed already, issue a "repeated interface" error. 3172 */ 3173 void checkNotRepeated(DiagnosticPosition pos, Type it, Set<Symbol> its) { 3174 if (its.contains(it.tsym)) 3175 log.error(pos, Errors.RepeatedInterface); 3176 else { 3177 its.add(it.tsym); 3178 } 3179 } 3180 3181 /* ************************************************************************* 3182 * Check annotations 3183 **************************************************************************/ 3184 3185 /** 3186 * Recursively validate annotations values 3187 */ 3188 void validateAnnotationTree(JCTree tree) { 3189 class AnnotationValidator extends TreeScanner { 3190 @Override 3191 public void visitAnnotation(JCAnnotation tree) { 3192 if (!tree.type.isErroneous() && tree.type.tsym.isAnnotationType()) { 3193 super.visitAnnotation(tree); 3194 validateAnnotation(tree); 3195 } 3196 } 3197 } 3198 tree.accept(new AnnotationValidator()); 3199 } 3200 3201 /** 3202 * {@literal 3203 * Annotation types are restricted to primitives, String, an 3204 * enum, an annotation, Class, Class<?>, Class<? extends 3205 * Anything>, arrays of the preceding. 3206 * } 3207 */ 3208 void validateAnnotationType(JCTree restype) { 3209 // restype may be null if an error occurred, so don't bother validating it 3210 if (restype != null) { 3211 validateAnnotationType(restype.pos(), restype.type); 3212 } 3213 } 3214 3215 void validateAnnotationType(DiagnosticPosition pos, Type type) { 3216 if (type.isPrimitive()) return; 3217 if (types.isSameType(type, syms.stringType)) return; 3218 if ((type.tsym.flags() & Flags.ENUM) != 0) return; 3219 if ((type.tsym.flags() & Flags.ANNOTATION) != 0) return; 3220 if (types.cvarLowerBound(type).tsym == syms.classType.tsym) return; 3221 if (types.isArray(type) && !types.isArray(types.elemtype(type))) { 3222 validateAnnotationType(pos, types.elemtype(type)); 3223 return; 3224 } 3225 log.error(pos, Errors.InvalidAnnotationMemberType); 3226 } 3227 3228 /** 3229 * "It is also a compile-time error if any method declared in an 3230 * annotation type has a signature that is override-equivalent to 3231 * that of any public or protected method declared in class Object 3232 * or in the interface annotation.Annotation." 3233 * 3234 * @jls 9.6 Annotation Types 3235 */ 3236 void validateAnnotationMethod(DiagnosticPosition pos, MethodSymbol m) { 3237 for (Type sup = syms.annotationType; sup.hasTag(CLASS); sup = types.supertype(sup)) { 3238 Scope s = sup.tsym.members(); 3239 for (Symbol sym : s.getSymbolsByName(m.name)) { 3240 if (sym.kind == MTH && 3241 (sym.flags() & (PUBLIC | PROTECTED)) != 0 && 3242 types.overrideEquivalent(m.type, sym.type)) 3243 log.error(pos, Errors.IntfAnnotationMemberClash(sym, sup)); 3244 } 3245 } 3246 } 3247 3248 /** Check the annotations of a symbol. 3249 */ 3250 public void validateAnnotations(List<JCAnnotation> annotations, JCTree declarationTree, Symbol s) { 3251 for (JCAnnotation a : annotations) 3252 validateAnnotation(a, declarationTree, s); 3253 } 3254 3255 /** Check the type annotations. 3256 */ 3257 public void validateTypeAnnotations(List<JCAnnotation> annotations, Symbol s, boolean isTypeParameter) { 3258 for (JCAnnotation a : annotations) 3259 validateTypeAnnotation(a, s, isTypeParameter); 3260 } 3261 3262 /** Check an annotation of a symbol. 3263 */ 3264 private void validateAnnotation(JCAnnotation a, JCTree declarationTree, Symbol s) { 3265 /** NOTE: if annotation processors are present, annotation processing rounds can happen after this method, 3266 * this can impact in particular records for which annotations are forcibly propagated. 3267 */ 3268 validateAnnotationTree(a); 3269 boolean isRecordMember = ((s.flags_field & RECORD) != 0 || s.enclClass() != null && s.enclClass().isRecord()); 3270 3271 boolean isRecordField = (s.flags_field & RECORD) != 0 && 3272 declarationTree.hasTag(VARDEF) && 3273 s.owner.kind == TYP; 3274 3275 if (isRecordField) { 3276 // first we need to check if the annotation is applicable to records 3277 Name[] targets = getTargetNames(a); 3278 boolean appliesToRecords = false; 3279 for (Name target : targets) { 3280 appliesToRecords = 3281 target == names.FIELD || 3282 target == names.PARAMETER || 3283 target == names.METHOD || 3284 target == names.TYPE_USE || 3285 target == names.RECORD_COMPONENT; 3286 if (appliesToRecords) { 3287 break; 3288 } 3289 } 3290 if (!appliesToRecords) { 3291 log.error(a.pos(), Errors.AnnotationTypeNotApplicable); 3292 } else { 3293 /* lets now find the annotations in the field that are targeted to record components and append them to 3294 * the corresponding record component 3295 */ 3296 ClassSymbol recordClass = (ClassSymbol) s.owner; 3297 RecordComponent rc = recordClass.getRecordComponent((VarSymbol)s); 3298 SymbolMetadata metadata = rc.getMetadata(); 3299 if (metadata == null || metadata.isEmpty()) { 3300 /* if not is empty then we have already been here, which is the case if multiple annotations are applied 3301 * to the record component declaration 3302 */ 3303 rc.appendAttributes(s.getRawAttributes().stream().filter(anno -> 3304 Arrays.stream(getTargetNames(anno.type.tsym)).anyMatch(name -> name == names.RECORD_COMPONENT) 3305 ).collect(List.collector())); 3306 3307 JCVariableDecl fieldAST = (JCVariableDecl) declarationTree; 3308 for (JCAnnotation fieldAnnot : fieldAST.mods.annotations) { 3309 for (JCAnnotation rcAnnot : rc.declarationFor().mods.annotations) { 3310 if (rcAnnot.pos == fieldAnnot.pos) { 3311 rcAnnot.setType(fieldAnnot.type); 3312 break; 3313 } 3314 } 3315 } 3316 3317 /* At this point, we used to carry over any type annotations from the VARDEF to the record component, but 3318 * that is problematic, since we get here only when *some* annotation is applied to the SE5 (declaration) 3319 * annotation location, inadvertently failing to carry over the type annotations when the VarDef has no 3320 * annotations in the SE5 annotation location. 3321 * 3322 * Now type annotations are assigned to record components in a method that would execute irrespective of 3323 * whether there are SE5 annotations on a VarDef viz com.sun.tools.javac.code.TypeAnnotations.TypeAnnotationPositions.visitVarDef 3324 */ 3325 } 3326 } 3327 } 3328 3329 /* the section below is tricky. Annotations applied to record components are propagated to the corresponding 3330 * record member so if an annotation has target: FIELD, it is propagated to the corresponding FIELD, if it has 3331 * target METHOD, it is propagated to the accessor and so on. But at the moment when method members are generated 3332 * there is no enough information to propagate only the right annotations. So all the annotations are propagated 3333 * to all the possible locations. 3334 * 3335 * At this point we need to remove all the annotations that are not in place before going on with the annotation 3336 * party. On top of the above there is the issue that there is no AST representing record components, just symbols 3337 * so the corresponding field has been holding all the annotations and it's metadata has been modified as if it 3338 * was both a field and a record component. 3339 * 3340 * So there are two places where we need to trim annotations from: the metadata of the symbol and / or the modifiers 3341 * in the AST. Whatever is in the metadata will be written to the class file, whatever is in the modifiers could 3342 * be see by annotation processors. 3343 * 3344 * The metadata contains both type annotations and declaration annotations. At this point of the game we don't 3345 * need to care about type annotations, they are all in the right place. But we could need to remove declaration 3346 * annotations. So for declaration annotations if they are not applicable to the record member, excluding type 3347 * annotations which are already correct, then we will remove it. For the AST modifiers if the annotation is not 3348 * applicable either as type annotation and or declaration annotation, only in that case it will be removed. 3349 * 3350 * So it could be that annotation is removed as a declaration annotation but it is kept in the AST modifier for 3351 * further inspection by annotation processors. 3352 * 3353 * For example: 3354 * 3355 * import java.lang.annotation.*; 3356 * 3357 * @Target({ElementType.TYPE_USE, ElementType.RECORD_COMPONENT}) 3358 * @Retention(RetentionPolicy.RUNTIME) 3359 * @interface Anno { } 3360 * 3361 * record R(@Anno String s) {} 3362 * 3363 * at this point we will have for the case of the generated field: 3364 * - @Anno in the modifier 3365 * - @Anno as a type annotation 3366 * - @Anno as a declaration annotation 3367 * 3368 * the last one should be removed because the annotation has not FIELD as target but it was applied as a 3369 * declaration annotation because the field was being treated both as a field and as a record component 3370 * as we have already copied the annotations to the record component, now the field doesn't need to hold 3371 * annotations that are not intended for it anymore. Still @Anno has to be kept in the AST's modifiers as it 3372 * is applicable as a type annotation to the type of the field. 3373 */ 3374 3375 if (a.type.tsym.isAnnotationType()) { 3376 Optional<Set<Name>> applicableTargetsOp = getApplicableTargets(a, s); 3377 if (!applicableTargetsOp.isEmpty()) { 3378 Set<Name> applicableTargets = applicableTargetsOp.get(); 3379 boolean notApplicableOrIsTypeUseOnly = applicableTargets.isEmpty() || 3380 applicableTargets.size() == 1 && applicableTargets.contains(names.TYPE_USE); 3381 boolean isCompGeneratedRecordElement = isRecordMember && (s.flags_field & Flags.GENERATED_MEMBER) != 0; 3382 boolean isCompRecordElementWithNonApplicableDeclAnno = isCompGeneratedRecordElement && notApplicableOrIsTypeUseOnly; 3383 3384 if (applicableTargets.isEmpty() || isCompRecordElementWithNonApplicableDeclAnno) { 3385 if (isCompRecordElementWithNonApplicableDeclAnno) { 3386 /* so we have found an annotation that is not applicable to a record member that was generated by the 3387 * compiler. This was intentionally done at TypeEnter, now is the moment strip away the annotations 3388 * that are not applicable to the given record member 3389 */ 3390 JCModifiers modifiers = TreeInfo.getModifiers(declarationTree); 3391 /* lets first remove the annotation from the modifier if it is not applicable, we have to check again as 3392 * it could be a type annotation 3393 */ 3394 if (modifiers != null && applicableTargets.isEmpty()) { 3395 ListBuffer<JCAnnotation> newAnnotations = new ListBuffer<>(); 3396 for (JCAnnotation anno : modifiers.annotations) { 3397 if (anno != a) { 3398 newAnnotations.add(anno); 3399 } 3400 } 3401 modifiers.annotations = newAnnotations.toList(); 3402 } 3403 // now lets remove it from the symbol 3404 s.getMetadata().removeDeclarationMetadata(a.attribute); 3405 } else { 3406 log.error(a.pos(), Errors.AnnotationTypeNotApplicable); 3407 } 3408 } 3409 /* if we are seeing the @SafeVarargs annotation applied to a compiler generated accessor, 3410 * then this is an error as we know that no compiler generated accessor will be a varargs 3411 * method, better to fail asap 3412 */ 3413 if (isCompGeneratedRecordElement && !isRecordField && a.type.tsym == syms.trustMeType.tsym && declarationTree.hasTag(METHODDEF)) { 3414 log.error(a.pos(), Errors.VarargsInvalidTrustmeAnno(syms.trustMeType.tsym, Fragments.VarargsTrustmeOnNonVarargsAccessor(s))); 3415 } 3416 } 3417 } 3418 3419 if (a.annotationType.type.tsym == syms.functionalInterfaceType.tsym) { 3420 if (s.kind != TYP) { 3421 log.error(a.pos(), Errors.BadFunctionalIntfAnno); 3422 } else if (!s.isInterface() || (s.flags() & ANNOTATION) != 0) { 3423 log.error(a.pos(), Errors.BadFunctionalIntfAnno1(Fragments.NotAFunctionalIntf(s))); 3424 } 3425 } 3426 } 3427 3428 public void validateTypeAnnotation(JCAnnotation a, Symbol s, boolean isTypeParameter) { 3429 Assert.checkNonNull(a.type); 3430 // we just want to validate that the anotation doesn't have any wrong target 3431 if (s != null) getApplicableTargets(a, s); 3432 validateAnnotationTree(a); 3433 3434 if (a.hasTag(TYPE_ANNOTATION) && 3435 !a.annotationType.type.isErroneous() && 3436 !isTypeAnnotation(a, isTypeParameter)) { 3437 log.error(a.pos(), Errors.AnnotationTypeNotApplicableToType(a.type)); 3438 } 3439 } 3440 3441 /** 3442 * Validate the proposed container 'repeatable' on the 3443 * annotation type symbol 's'. Report errors at position 3444 * 'pos'. 3445 * 3446 * @param s The (annotation)type declaration annotated with a @Repeatable 3447 * @param repeatable the @Repeatable on 's' 3448 * @param pos where to report errors 3449 */ 3450 public void validateRepeatable(TypeSymbol s, Attribute.Compound repeatable, DiagnosticPosition pos) { 3451 Assert.check(types.isSameType(repeatable.type, syms.repeatableType)); 3452 3453 Type t = null; 3454 List<Pair<MethodSymbol,Attribute>> l = repeatable.values; 3455 if (!l.isEmpty()) { 3456 Assert.check(l.head.fst.name == names.value); 3457 if (l.head.snd instanceof Attribute.Class) { 3458 t = ((Attribute.Class)l.head.snd).getValue(); 3459 } 3460 } 3461 3462 if (t == null) { 3463 // errors should already have been reported during Annotate 3464 return; 3465 } 3466 3467 validateValue(t.tsym, s, pos); 3468 validateRetention(t.tsym, s, pos); 3469 validateDocumented(t.tsym, s, pos); 3470 validateInherited(t.tsym, s, pos); 3471 validateTarget(t.tsym, s, pos); 3472 validateDefault(t.tsym, pos); 3473 } 3474 3475 private void validateValue(TypeSymbol container, TypeSymbol contained, DiagnosticPosition pos) { 3476 Symbol sym = container.members().findFirst(names.value); 3477 if (sym != null && sym.kind == MTH) { 3478 MethodSymbol m = (MethodSymbol) sym; 3479 Type ret = m.getReturnType(); 3480 if (!(ret.hasTag(ARRAY) && types.isSameType(((ArrayType)ret).elemtype, contained.type))) { 3481 log.error(pos, 3482 Errors.InvalidRepeatableAnnotationValueReturn(container, 3483 ret, 3484 types.makeArrayType(contained.type))); 3485 } 3486 } else { 3487 log.error(pos, Errors.InvalidRepeatableAnnotationNoValue(container)); 3488 } 3489 } 3490 3491 private void validateRetention(TypeSymbol container, TypeSymbol contained, DiagnosticPosition pos) { 3492 Attribute.RetentionPolicy containerRetention = types.getRetention(container); 3493 Attribute.RetentionPolicy containedRetention = types.getRetention(contained); 3494 3495 boolean error = false; 3496 switch (containedRetention) { 3497 case RUNTIME: 3498 if (containerRetention != Attribute.RetentionPolicy.RUNTIME) { 3499 error = true; 3500 } 3501 break; 3502 case CLASS: 3503 if (containerRetention == Attribute.RetentionPolicy.SOURCE) { 3504 error = true; 3505 } 3506 } 3507 if (error ) { 3508 log.error(pos, 3509 Errors.InvalidRepeatableAnnotationRetention(container, 3510 containerRetention.name(), 3511 contained, 3512 containedRetention.name())); 3513 } 3514 } 3515 3516 private void validateDocumented(Symbol container, Symbol contained, DiagnosticPosition pos) { 3517 if (contained.attribute(syms.documentedType.tsym) != null) { 3518 if (container.attribute(syms.documentedType.tsym) == null) { 3519 log.error(pos, Errors.InvalidRepeatableAnnotationNotDocumented(container, contained)); 3520 } 3521 } 3522 } 3523 3524 private void validateInherited(Symbol container, Symbol contained, DiagnosticPosition pos) { 3525 if (contained.attribute(syms.inheritedType.tsym) != null) { 3526 if (container.attribute(syms.inheritedType.tsym) == null) { 3527 log.error(pos, Errors.InvalidRepeatableAnnotationNotInherited(container, contained)); 3528 } 3529 } 3530 } 3531 3532 private void validateTarget(TypeSymbol container, TypeSymbol contained, DiagnosticPosition pos) { 3533 // The set of targets the container is applicable to must be a subset 3534 // (with respect to annotation target semantics) of the set of targets 3535 // the contained is applicable to. The target sets may be implicit or 3536 // explicit. 3537 3538 Set<Name> containerTargets; 3539 Attribute.Array containerTarget = getAttributeTargetAttribute(container); 3540 if (containerTarget == null) { 3541 containerTargets = getDefaultTargetSet(); 3542 } else { 3543 containerTargets = new HashSet<>(); 3544 for (Attribute app : containerTarget.values) { 3545 if (!(app instanceof Attribute.Enum attributeEnum)) { 3546 continue; // recovery 3547 } 3548 containerTargets.add(attributeEnum.value.name); 3549 } 3550 } 3551 3552 Set<Name> containedTargets; 3553 Attribute.Array containedTarget = getAttributeTargetAttribute(contained); 3554 if (containedTarget == null) { 3555 containedTargets = getDefaultTargetSet(); 3556 } else { 3557 containedTargets = new HashSet<>(); 3558 for (Attribute app : containedTarget.values) { 3559 if (!(app instanceof Attribute.Enum attributeEnum)) { 3560 continue; // recovery 3561 } 3562 containedTargets.add(attributeEnum.value.name); 3563 } 3564 } 3565 3566 if (!isTargetSubsetOf(containerTargets, containedTargets)) { 3567 log.error(pos, Errors.InvalidRepeatableAnnotationIncompatibleTarget(container, contained)); 3568 } 3569 } 3570 3571 /* get a set of names for the default target */ 3572 private Set<Name> getDefaultTargetSet() { 3573 if (defaultTargets == null) { 3574 defaultTargets = Set.of(defaultTargetMetaInfo()); 3575 } 3576 3577 return defaultTargets; 3578 } 3579 private Set<Name> defaultTargets; 3580 3581 3582 /** Checks that s is a subset of t, with respect to ElementType 3583 * semantics, specifically {ANNOTATION_TYPE} is a subset of {TYPE}, 3584 * and {TYPE_USE} covers the set {ANNOTATION_TYPE, TYPE, TYPE_USE, 3585 * TYPE_PARAMETER}. 3586 */ 3587 private boolean isTargetSubsetOf(Set<Name> s, Set<Name> t) { 3588 // Check that all elements in s are present in t 3589 for (Name n2 : s) { 3590 boolean currentElementOk = false; 3591 for (Name n1 : t) { 3592 if (n1 == n2) { 3593 currentElementOk = true; 3594 break; 3595 } else if (n1 == names.TYPE && n2 == names.ANNOTATION_TYPE) { 3596 currentElementOk = true; 3597 break; 3598 } else if (n1 == names.TYPE_USE && 3599 (n2 == names.TYPE || 3600 n2 == names.ANNOTATION_TYPE || 3601 n2 == names.TYPE_PARAMETER)) { 3602 currentElementOk = true; 3603 break; 3604 } 3605 } 3606 if (!currentElementOk) 3607 return false; 3608 } 3609 return true; 3610 } 3611 3612 private void validateDefault(Symbol container, DiagnosticPosition pos) { 3613 // validate that all other elements of containing type has defaults 3614 Scope scope = container.members(); 3615 for(Symbol elm : scope.getSymbols()) { 3616 if (elm.name != names.value && 3617 elm.kind == MTH && 3618 ((MethodSymbol)elm).defaultValue == null) { 3619 log.error(pos, 3620 Errors.InvalidRepeatableAnnotationElemNondefault(container, elm)); 3621 } 3622 } 3623 } 3624 3625 /** Is s a method symbol that overrides a method in a superclass? */ 3626 boolean isOverrider(Symbol s) { 3627 if (s.kind != MTH || s.isStatic()) 3628 return false; 3629 MethodSymbol m = (MethodSymbol)s; 3630 TypeSymbol owner = (TypeSymbol)m.owner; 3631 for (Type sup : types.closure(owner.type)) { 3632 if (sup == owner.type) 3633 continue; // skip "this" 3634 Scope scope = sup.tsym.members(); 3635 for (Symbol sym : scope.getSymbolsByName(m.name)) { 3636 if (!sym.isStatic() && m.overrides(sym, owner, types, true)) 3637 return true; 3638 } 3639 } 3640 return false; 3641 } 3642 3643 /** Is the annotation applicable to types? */ 3644 protected boolean isTypeAnnotation(JCAnnotation a, boolean isTypeParameter) { 3645 List<Attribute> targets = typeAnnotations.annotationTargets(a.annotationType.type.tsym); 3646 return (targets == null) ? 3647 (Feature.NO_TARGET_ANNOTATION_APPLICABILITY.allowedInSource(source) && isTypeParameter) : 3648 targets.stream() 3649 .anyMatch(attr -> isTypeAnnotation(attr, isTypeParameter)); 3650 } 3651 //where 3652 boolean isTypeAnnotation(Attribute a, boolean isTypeParameter) { 3653 Attribute.Enum e = (Attribute.Enum)a; 3654 return (e.value.name == names.TYPE_USE || 3655 (isTypeParameter && e.value.name == names.TYPE_PARAMETER)); 3656 } 3657 3658 /** Is the annotation applicable to the symbol? */ 3659 Name[] getTargetNames(JCAnnotation a) { 3660 return getTargetNames(a.annotationType.type.tsym); 3661 } 3662 3663 public Name[] getTargetNames(TypeSymbol annoSym) { 3664 Attribute.Array arr = getAttributeTargetAttribute(annoSym); 3665 Name[] targets; 3666 if (arr == null) { 3667 targets = defaultTargetMetaInfo(); 3668 } else { 3669 // TODO: can we optimize this? 3670 targets = new Name[arr.values.length]; 3671 for (int i=0; i<arr.values.length; ++i) { 3672 Attribute app = arr.values[i]; 3673 if (!(app instanceof Attribute.Enum attributeEnum)) { 3674 return new Name[0]; 3675 } 3676 targets[i] = attributeEnum.value.name; 3677 } 3678 } 3679 return targets; 3680 } 3681 3682 boolean annotationApplicable(JCAnnotation a, Symbol s) { 3683 Optional<Set<Name>> targets = getApplicableTargets(a, s); 3684 /* the optional could be empty if the annotation is unknown in that case 3685 * we return that it is applicable and if it is erroneous that should imply 3686 * an error at the declaration site 3687 */ 3688 return targets.isEmpty() || targets.isPresent() && !targets.get().isEmpty(); 3689 } 3690 3691 Optional<Set<Name>> getApplicableTargets(JCAnnotation a, Symbol s) { 3692 Attribute.Array arr = getAttributeTargetAttribute(a.annotationType.type.tsym); 3693 Name[] targets; 3694 Set<Name> applicableTargets = new HashSet<>(); 3695 3696 if (arr == null) { 3697 targets = defaultTargetMetaInfo(); 3698 } else { 3699 // TODO: can we optimize this? 3700 targets = new Name[arr.values.length]; 3701 for (int i=0; i<arr.values.length; ++i) { 3702 Attribute app = arr.values[i]; 3703 if (!(app instanceof Attribute.Enum attributeEnum)) { 3704 // recovery 3705 return Optional.empty(); 3706 } 3707 targets[i] = attributeEnum.value.name; 3708 } 3709 } 3710 for (Name target : targets) { 3711 if (target == names.TYPE) { 3712 if (s.kind == TYP) 3713 applicableTargets.add(names.TYPE); 3714 } else if (target == names.FIELD) { 3715 if (s.kind == VAR && s.owner.kind != MTH) 3716 applicableTargets.add(names.FIELD); 3717 } else if (target == names.RECORD_COMPONENT) { 3718 if (s.getKind() == ElementKind.RECORD_COMPONENT) { 3719 applicableTargets.add(names.RECORD_COMPONENT); 3720 } 3721 } else if (target == names.METHOD) { 3722 if (s.kind == MTH && !s.isConstructor()) 3723 applicableTargets.add(names.METHOD); 3724 } else if (target == names.PARAMETER) { 3725 if (s.kind == VAR && 3726 (s.owner.kind == MTH && (s.flags() & PARAMETER) != 0)) { 3727 applicableTargets.add(names.PARAMETER); 3728 } 3729 } else if (target == names.CONSTRUCTOR) { 3730 if (s.kind == MTH && s.isConstructor()) 3731 applicableTargets.add(names.CONSTRUCTOR); 3732 } else if (target == names.LOCAL_VARIABLE) { 3733 if (s.kind == VAR && s.owner.kind == MTH && 3734 (s.flags() & PARAMETER) == 0) { 3735 applicableTargets.add(names.LOCAL_VARIABLE); 3736 } 3737 } else if (target == names.ANNOTATION_TYPE) { 3738 if (s.kind == TYP && (s.flags() & ANNOTATION) != 0) { 3739 applicableTargets.add(names.ANNOTATION_TYPE); 3740 } 3741 } else if (target == names.PACKAGE) { 3742 if (s.kind == PCK) 3743 applicableTargets.add(names.PACKAGE); 3744 } else if (target == names.TYPE_USE) { 3745 if (s.kind == VAR && s.owner.kind == MTH && s.type.hasTag(NONE)) { 3746 //cannot type annotate implicitly typed locals 3747 continue; 3748 } else if (s.kind == TYP || s.kind == VAR || 3749 (s.kind == MTH && !s.isConstructor() && 3750 !s.type.getReturnType().hasTag(VOID)) || 3751 (s.kind == MTH && s.isConstructor())) { 3752 applicableTargets.add(names.TYPE_USE); 3753 } 3754 } else if (target == names.TYPE_PARAMETER) { 3755 if (s.kind == TYP && s.type.hasTag(TYPEVAR)) 3756 applicableTargets.add(names.TYPE_PARAMETER); 3757 } else if (target == names.MODULE) { 3758 if (s.kind == MDL) 3759 applicableTargets.add(names.MODULE); 3760 } else { 3761 log.error(a, Errors.AnnotationUnrecognizedAttributeName(a.type, target)); 3762 return Optional.empty(); // Unknown ElementType 3763 } 3764 } 3765 return Optional.of(applicableTargets); 3766 } 3767 3768 Attribute.Array getAttributeTargetAttribute(TypeSymbol s) { 3769 Attribute.Compound atTarget = s.getAnnotationTypeMetadata().getTarget(); 3770 if (atTarget == null) return null; // ok, is applicable 3771 Attribute atValue = atTarget.member(names.value); 3772 return (atValue instanceof Attribute.Array attributeArray) ? attributeArray : null; 3773 } 3774 3775 private Name[] dfltTargetMeta; 3776 private Name[] defaultTargetMetaInfo() { 3777 if (dfltTargetMeta == null) { 3778 ArrayList<Name> defaultTargets = new ArrayList<>(); 3779 defaultTargets.add(names.PACKAGE); 3780 defaultTargets.add(names.TYPE); 3781 defaultTargets.add(names.FIELD); 3782 defaultTargets.add(names.METHOD); 3783 defaultTargets.add(names.CONSTRUCTOR); 3784 defaultTargets.add(names.ANNOTATION_TYPE); 3785 defaultTargets.add(names.LOCAL_VARIABLE); 3786 defaultTargets.add(names.PARAMETER); 3787 if (allowRecords) { 3788 defaultTargets.add(names.RECORD_COMPONENT); 3789 } 3790 if (allowModules) { 3791 defaultTargets.add(names.MODULE); 3792 } 3793 dfltTargetMeta = defaultTargets.toArray(new Name[0]); 3794 } 3795 return dfltTargetMeta; 3796 } 3797 3798 /** Check an annotation value. 3799 * 3800 * @param a The annotation tree to check 3801 * @return true if this annotation tree is valid, otherwise false 3802 */ 3803 public boolean validateAnnotationDeferErrors(JCAnnotation a) { 3804 boolean res = false; 3805 final Log.DiagnosticHandler diagHandler = new Log.DiscardDiagnosticHandler(log); 3806 try { 3807 res = validateAnnotation(a); 3808 } finally { 3809 log.popDiagnosticHandler(diagHandler); 3810 } 3811 return res; 3812 } 3813 3814 private boolean validateAnnotation(JCAnnotation a) { 3815 boolean isValid = true; 3816 AnnotationTypeMetadata metadata = a.annotationType.type.tsym.getAnnotationTypeMetadata(); 3817 3818 // collect an inventory of the annotation elements 3819 Set<MethodSymbol> elements = metadata.getAnnotationElements(); 3820 3821 // remove the ones that are assigned values 3822 for (JCTree arg : a.args) { 3823 if (!arg.hasTag(ASSIGN)) continue; // recovery 3824 JCAssign assign = (JCAssign)arg; 3825 Symbol m = TreeInfo.symbol(assign.lhs); 3826 if (m == null || m.type.isErroneous()) continue; 3827 if (!elements.remove(m)) { 3828 isValid = false; 3829 log.error(assign.lhs.pos(), 3830 Errors.DuplicateAnnotationMemberValue(m.name, a.type)); 3831 } 3832 } 3833 3834 // all the remaining ones better have default values 3835 List<Name> missingDefaults = List.nil(); 3836 Set<MethodSymbol> membersWithDefault = metadata.getAnnotationElementsWithDefault(); 3837 for (MethodSymbol m : elements) { 3838 if (m.type.isErroneous()) 3839 continue; 3840 3841 if (!membersWithDefault.contains(m)) 3842 missingDefaults = missingDefaults.append(m.name); 3843 } 3844 missingDefaults = missingDefaults.reverse(); 3845 if (missingDefaults.nonEmpty()) { 3846 isValid = false; 3847 Error errorKey = (missingDefaults.size() > 1) 3848 ? Errors.AnnotationMissingDefaultValue1(a.type, missingDefaults) 3849 : Errors.AnnotationMissingDefaultValue(a.type, missingDefaults); 3850 log.error(a.pos(), errorKey); 3851 } 3852 3853 return isValid && validateTargetAnnotationValue(a); 3854 } 3855 3856 /* Validate the special java.lang.annotation.Target annotation */ 3857 boolean validateTargetAnnotationValue(JCAnnotation a) { 3858 // special case: java.lang.annotation.Target must not have 3859 // repeated values in its value member 3860 if (a.annotationType.type.tsym != syms.annotationTargetType.tsym || 3861 a.args.tail == null) 3862 return true; 3863 3864 boolean isValid = true; 3865 if (!a.args.head.hasTag(ASSIGN)) return false; // error recovery 3866 JCAssign assign = (JCAssign) a.args.head; 3867 Symbol m = TreeInfo.symbol(assign.lhs); 3868 if (m.name != names.value) return false; 3869 JCTree rhs = assign.rhs; 3870 if (!rhs.hasTag(NEWARRAY)) return false; 3871 JCNewArray na = (JCNewArray) rhs; 3872 Set<Symbol> targets = new HashSet<>(); 3873 for (JCTree elem : na.elems) { 3874 if (!targets.add(TreeInfo.symbol(elem))) { 3875 isValid = false; 3876 log.error(elem.pos(), Errors.RepeatedAnnotationTarget); 3877 } 3878 } 3879 return isValid; 3880 } 3881 3882 void checkDeprecatedAnnotation(DiagnosticPosition pos, Symbol s) { 3883 if (lint.isEnabled(LintCategory.DEP_ANN) && s.isDeprecatableViaAnnotation() && 3884 (s.flags() & DEPRECATED) != 0 && 3885 !syms.deprecatedType.isErroneous() && 3886 s.attribute(syms.deprecatedType.tsym) == null) { 3887 log.warning(LintCategory.DEP_ANN, 3888 pos, Warnings.MissingDeprecatedAnnotation); 3889 } 3890 // Note: @Deprecated has no effect on local variables, parameters and package decls. 3891 if (lint.isEnabled(LintCategory.DEPRECATION) && !s.isDeprecatableViaAnnotation()) { 3892 if (!syms.deprecatedType.isErroneous() && s.attribute(syms.deprecatedType.tsym) != null) { 3893 log.warning(LintCategory.DEPRECATION, pos, 3894 Warnings.DeprecatedAnnotationHasNoEffect(Kinds.kindName(s))); 3895 } 3896 } 3897 } 3898 3899 void checkDeprecated(final DiagnosticPosition pos, final Symbol other, final Symbol s) { 3900 checkDeprecated(() -> pos, other, s); 3901 } 3902 3903 void checkDeprecated(Supplier<DiagnosticPosition> pos, final Symbol other, final Symbol s) { 3904 if ( (s.isDeprecatedForRemoval() 3905 || s.isDeprecated() && !other.isDeprecated()) 3906 && (s.outermostClass() != other.outermostClass() || s.outermostClass() == null) 3907 && s.kind != Kind.PCK) { 3908 deferredLintHandler.report(_l -> warnDeprecated(pos.get(), s)); 3909 } 3910 } 3911 3912 void checkSunAPI(final DiagnosticPosition pos, final Symbol s) { 3913 if ((s.flags() & PROPRIETARY) != 0) { 3914 deferredLintHandler.report(_l -> { 3915 log.mandatoryWarning(pos, Warnings.SunProprietary(s)); 3916 }); 3917 } 3918 } 3919 3920 void checkProfile(final DiagnosticPosition pos, final Symbol s) { 3921 if (profile != Profile.DEFAULT && (s.flags() & NOT_IN_PROFILE) != 0) { 3922 log.error(pos, Errors.NotInProfile(s, profile)); 3923 } 3924 } 3925 3926 void checkPreview(DiagnosticPosition pos, Symbol other, Symbol s) { 3927 if ((s.flags() & PREVIEW_API) != 0 && !preview.participatesInPreview(syms, other, s) && !disablePreviewCheck) { 3928 if ((s.flags() & PREVIEW_REFLECTIVE) == 0) { 3929 if (!preview.isEnabled()) { 3930 log.error(pos, Errors.IsPreview(s)); 3931 } else { 3932 preview.markUsesPreview(pos); 3933 deferredLintHandler.report(_l -> warnPreviewAPI(pos, Warnings.IsPreview(s))); 3934 } 3935 } else { 3936 deferredLintHandler.report(_l -> warnPreviewAPI(pos, Warnings.IsPreviewReflective(s))); 3937 } 3938 } 3939 if (preview.declaredUsingPreviewFeature(s)) { 3940 if (preview.isEnabled()) { 3941 //for preview disabled do presumably so not need to do anything? 3942 //If "s" is compiled from source, then there was an error for it already; 3943 //if "s" is from classfile, there already was an error for the classfile. 3944 preview.markUsesPreview(pos); 3945 deferredLintHandler.report(_l -> warnDeclaredUsingPreview(pos, s)); 3946 } 3947 } 3948 } 3949 3950 void checkRestricted(DiagnosticPosition pos, Symbol s) { 3951 if (s.kind == MTH && (s.flags() & RESTRICTED) != 0) { 3952 deferredLintHandler.report(_l -> warnRestrictedAPI(pos, s)); 3953 } 3954 } 3955 3956 /* ************************************************************************* 3957 * Check for recursive annotation elements. 3958 **************************************************************************/ 3959 3960 /** Check for cycles in the graph of annotation elements. 3961 */ 3962 void checkNonCyclicElements(JCClassDecl tree) { 3963 if ((tree.sym.flags_field & ANNOTATION) == 0) return; 3964 Assert.check((tree.sym.flags_field & LOCKED) == 0); 3965 try { 3966 tree.sym.flags_field |= LOCKED; 3967 for (JCTree def : tree.defs) { 3968 if (!def.hasTag(METHODDEF)) continue; 3969 JCMethodDecl meth = (JCMethodDecl)def; 3970 checkAnnotationResType(meth.pos(), meth.restype.type); 3971 } 3972 } finally { 3973 tree.sym.flags_field &= ~LOCKED; 3974 tree.sym.flags_field |= ACYCLIC_ANN; 3975 } 3976 } 3977 3978 void checkNonCyclicElementsInternal(DiagnosticPosition pos, TypeSymbol tsym) { 3979 if ((tsym.flags_field & ACYCLIC_ANN) != 0) 3980 return; 3981 if ((tsym.flags_field & LOCKED) != 0) { 3982 log.error(pos, Errors.CyclicAnnotationElement(tsym)); 3983 return; 3984 } 3985 try { 3986 tsym.flags_field |= LOCKED; 3987 for (Symbol s : tsym.members().getSymbols(NON_RECURSIVE)) { 3988 if (s.kind != MTH) 3989 continue; 3990 checkAnnotationResType(pos, ((MethodSymbol)s).type.getReturnType()); 3991 } 3992 } finally { 3993 tsym.flags_field &= ~LOCKED; 3994 tsym.flags_field |= ACYCLIC_ANN; 3995 } 3996 } 3997 3998 void checkAnnotationResType(DiagnosticPosition pos, Type type) { 3999 switch (type.getTag()) { 4000 case CLASS: 4001 if ((type.tsym.flags() & ANNOTATION) != 0) 4002 checkNonCyclicElementsInternal(pos, type.tsym); 4003 break; 4004 case ARRAY: 4005 checkAnnotationResType(pos, types.elemtype(type)); 4006 break; 4007 default: 4008 break; // int etc 4009 } 4010 } 4011 4012 /* ************************************************************************* 4013 * Check for cycles in the constructor call graph. 4014 **************************************************************************/ 4015 4016 /** Check for cycles in the graph of constructors calling other 4017 * constructors. 4018 */ 4019 void checkCyclicConstructors(JCClassDecl tree) { 4020 // use LinkedHashMap so we generate errors deterministically 4021 Map<Symbol,Symbol> callMap = new LinkedHashMap<>(); 4022 4023 // enter each constructor this-call into the map 4024 for (List<JCTree> l = tree.defs; l.nonEmpty(); l = l.tail) { 4025 if (!TreeInfo.isConstructor(l.head)) 4026 continue; 4027 JCMethodDecl meth = (JCMethodDecl)l.head; 4028 JCMethodInvocation app = TreeInfo.findConstructorCall(meth); 4029 if (app != null && TreeInfo.name(app.meth) == names._this) { 4030 callMap.put(meth.sym, TreeInfo.symbol(app.meth)); 4031 } else { 4032 meth.sym.flags_field |= ACYCLIC; 4033 } 4034 } 4035 4036 // Check for cycles in the map 4037 Symbol[] ctors = new Symbol[0]; 4038 ctors = callMap.keySet().toArray(ctors); 4039 for (Symbol caller : ctors) { 4040 checkCyclicConstructor(tree, caller, callMap); 4041 } 4042 } 4043 4044 /** Look in the map to see if the given constructor is part of a 4045 * call cycle. 4046 */ 4047 private void checkCyclicConstructor(JCClassDecl tree, Symbol ctor, 4048 Map<Symbol,Symbol> callMap) { 4049 if (ctor != null && (ctor.flags_field & ACYCLIC) == 0) { 4050 if ((ctor.flags_field & LOCKED) != 0) { 4051 log.error(TreeInfo.diagnosticPositionFor(ctor, tree, false, t -> t.hasTag(IDENT)), 4052 Errors.RecursiveCtorInvocation); 4053 } else { 4054 ctor.flags_field |= LOCKED; 4055 checkCyclicConstructor(tree, callMap.remove(ctor), callMap); 4056 ctor.flags_field &= ~LOCKED; 4057 } 4058 ctor.flags_field |= ACYCLIC; 4059 } 4060 } 4061 4062 /* ************************************************************************* 4063 * Verify the proper placement of super()/this() calls. 4064 * 4065 * - super()/this() may only appear in constructors 4066 * - There must be at most one super()/this() call per constructor 4067 * - The super()/this() call, if any, must be a top-level statement in the 4068 * constructor, i.e., not nested inside any other statement or block 4069 * - There must be no return statements prior to the super()/this() call 4070 **************************************************************************/ 4071 4072 void checkSuperInitCalls(JCClassDecl tree) { 4073 new SuperThisChecker().check(tree); 4074 } 4075 4076 private class SuperThisChecker extends TreeScanner { 4077 4078 // Match this scan stack: 1=JCMethodDecl, 2=JCExpressionStatement, 3=JCMethodInvocation 4079 private static final int MATCH_SCAN_DEPTH = 3; 4080 4081 private boolean constructor; // is this method a constructor? 4082 private boolean firstStatement; // at the first statement in method? 4083 private JCReturn earlyReturn; // first return prior to the super()/init(), if any 4084 private Name initCall; // whichever of "super" or "init" we've seen already 4085 private int scanDepth; // current scan recursion depth in method body 4086 4087 public void check(JCClassDecl classDef) { 4088 scan(classDef.defs); 4089 } 4090 4091 @Override 4092 public void visitMethodDef(JCMethodDecl tree) { 4093 Assert.check(!constructor); 4094 Assert.check(earlyReturn == null); 4095 Assert.check(initCall == null); 4096 Assert.check(scanDepth == 1); 4097 4098 // Initialize state for this method 4099 constructor = TreeInfo.isConstructor(tree); 4100 try { 4101 4102 // Scan method body 4103 if (tree.body != null) { 4104 firstStatement = true; 4105 for (List<JCStatement> l = tree.body.stats; l.nonEmpty(); l = l.tail) { 4106 scan(l.head); 4107 firstStatement = false; 4108 } 4109 } 4110 4111 // Verify no 'return' seen prior to an explicit super()/this() call 4112 if (constructor && earlyReturn != null && initCall != null) 4113 log.error(earlyReturn.pos(), Errors.ReturnBeforeSuperclassInitialized); 4114 } finally { 4115 firstStatement = false; 4116 constructor = false; 4117 earlyReturn = null; 4118 initCall = null; 4119 } 4120 } 4121 4122 @Override 4123 public void scan(JCTree tree) { 4124 scanDepth++; 4125 try { 4126 super.scan(tree); 4127 } finally { 4128 scanDepth--; 4129 } 4130 } 4131 4132 @Override 4133 public void visitApply(JCMethodInvocation apply) { 4134 do { 4135 4136 // Is this a super() or this() call? 4137 Name methodName = TreeInfo.name(apply.meth); 4138 if (methodName != names._super && methodName != names._this) 4139 break; 4140 4141 // super()/this() calls must only appear in a constructor 4142 if (!constructor) { 4143 log.error(apply.pos(), Errors.CallMustOnlyAppearInCtor); 4144 break; 4145 } 4146 4147 // super()/this() calls must be a top level statement 4148 if (scanDepth != MATCH_SCAN_DEPTH) { 4149 log.error(apply.pos(), Errors.CtorCallsNotAllowedHere); 4150 break; 4151 } 4152 4153 // super()/this() calls must not appear more than once 4154 if (initCall != null) { 4155 log.error(apply.pos(), Errors.RedundantSuperclassInit); 4156 break; 4157 } 4158 4159 // If super()/this() isn't first, require flexible constructors feature 4160 if (!firstStatement) 4161 preview.checkSourceLevel(apply.pos(), Feature.FLEXIBLE_CONSTRUCTORS); 4162 4163 // We found a legitimate super()/this() call; remember it 4164 initCall = methodName; 4165 } while (false); 4166 4167 // Proceed 4168 super.visitApply(apply); 4169 } 4170 4171 @Override 4172 public void visitReturn(JCReturn tree) { 4173 if (constructor && initCall == null && earlyReturn == null) 4174 earlyReturn = tree; // we have seen a return but not (yet) a super()/this() 4175 super.visitReturn(tree); 4176 } 4177 4178 @Override 4179 public void visitClassDef(JCClassDecl tree) { 4180 // don't descend any further 4181 } 4182 } 4183 4184 /* ************************************************************************* 4185 * Miscellaneous 4186 **************************************************************************/ 4187 4188 /** 4189 * Check for division by integer constant zero 4190 * @param pos Position for error reporting. 4191 * @param operator The operator for the expression 4192 * @param operand The right hand operand for the expression 4193 */ 4194 void checkDivZero(final DiagnosticPosition pos, Symbol operator, Type operand) { 4195 if (operand.constValue() != null 4196 && operand.getTag().isSubRangeOf(LONG) 4197 && ((Number) (operand.constValue())).longValue() == 0) { 4198 int opc = ((OperatorSymbol)operator).opcode; 4199 if (opc == ByteCodes.idiv || opc == ByteCodes.imod 4200 || opc == ByteCodes.ldiv || opc == ByteCodes.lmod) { 4201 deferredLintHandler.report(_l -> warnDivZero(pos)); 4202 } 4203 } 4204 } 4205 4206 /** 4207 * Check for possible loss of precission 4208 * @param pos Position for error reporting. 4209 * @param found The computed type of the tree 4210 * @param req The computed type of the tree 4211 */ 4212 void checkLossOfPrecision(final DiagnosticPosition pos, Type found, Type req) { 4213 if (found.isNumeric() && req.isNumeric() && !types.isAssignable(found, req)) { 4214 deferredLintHandler.report(_l -> { 4215 if (lint.isEnabled(LintCategory.LOSSY_CONVERSIONS)) 4216 log.warning(LintCategory.LOSSY_CONVERSIONS, 4217 pos, Warnings.PossibleLossOfPrecision(found, req)); 4218 }); 4219 } 4220 } 4221 4222 /** 4223 * Check for empty statements after if 4224 */ 4225 void checkEmptyIf(JCIf tree) { 4226 if (tree.thenpart.hasTag(SKIP) && tree.elsepart == null && 4227 lint.isEnabled(LintCategory.EMPTY)) 4228 log.warning(LintCategory.EMPTY, tree.thenpart.pos(), Warnings.EmptyIf); 4229 } 4230 4231 /** Check that symbol is unique in given scope. 4232 * @param pos Position for error reporting. 4233 * @param sym The symbol. 4234 * @param s The scope. 4235 */ 4236 boolean checkUnique(DiagnosticPosition pos, Symbol sym, Scope s) { 4237 if (sym.type.isErroneous()) 4238 return true; 4239 if (sym.owner.name == names.any) return false; 4240 for (Symbol byName : s.getSymbolsByName(sym.name, NON_RECURSIVE)) { 4241 if (sym != byName && 4242 (byName.flags() & CLASH) == 0 && 4243 sym.kind == byName.kind && 4244 sym.name != names.error && 4245 (sym.kind != MTH || 4246 types.hasSameArgs(sym.type, byName.type) || 4247 types.hasSameArgs(types.erasure(sym.type), types.erasure(byName.type)))) { 4248 if ((sym.flags() & VARARGS) != (byName.flags() & VARARGS)) { 4249 sym.flags_field |= CLASH; 4250 varargsDuplicateError(pos, sym, byName); 4251 return true; 4252 } else if (sym.kind == MTH && !types.hasSameArgs(sym.type, byName.type, false)) { 4253 duplicateErasureError(pos, sym, byName); 4254 sym.flags_field |= CLASH; 4255 return true; 4256 } else if ((sym.flags() & MATCH_BINDING) != 0 && 4257 (byName.flags() & MATCH_BINDING) != 0 && 4258 (byName.flags() & MATCH_BINDING_TO_OUTER) == 0) { 4259 if (!sym.type.isErroneous()) { 4260 log.error(pos, Errors.MatchBindingExists); 4261 sym.flags_field |= CLASH; 4262 } 4263 return false; 4264 } else { 4265 duplicateError(pos, byName); 4266 return false; 4267 } 4268 } 4269 } 4270 return true; 4271 } 4272 4273 /** Report duplicate declaration error. 4274 */ 4275 void duplicateErasureError(DiagnosticPosition pos, Symbol sym1, Symbol sym2) { 4276 if (!sym1.type.isErroneous() && !sym2.type.isErroneous()) { 4277 log.error(pos, Errors.NameClashSameErasure(sym1, sym2)); 4278 } 4279 } 4280 4281 /**Check that types imported through the ordinary imports don't clash with types imported 4282 * by other (static or ordinary) imports. Note that two static imports may import two clashing 4283 * types without an error on the imports. 4284 * @param toplevel The toplevel tree for which the test should be performed. 4285 */ 4286 void checkImportsUnique(JCCompilationUnit toplevel) { 4287 WriteableScope ordinallyImportedSoFar = WriteableScope.create(toplevel.packge); 4288 WriteableScope staticallyImportedSoFar = WriteableScope.create(toplevel.packge); 4289 WriteableScope topLevelScope = toplevel.toplevelScope; 4290 4291 for (JCTree def : toplevel.defs) { 4292 if (!def.hasTag(IMPORT)) 4293 continue; 4294 4295 JCImport imp = (JCImport) def; 4296 4297 if (imp.importScope == null) 4298 continue; 4299 4300 for (Symbol sym : imp.importScope.getSymbols(sym -> sym.kind == TYP)) { 4301 if (imp.isStatic()) { 4302 checkUniqueImport(imp.pos(), ordinallyImportedSoFar, staticallyImportedSoFar, topLevelScope, sym, true); 4303 staticallyImportedSoFar.enter(sym); 4304 } else { 4305 checkUniqueImport(imp.pos(), ordinallyImportedSoFar, staticallyImportedSoFar, topLevelScope, sym, false); 4306 ordinallyImportedSoFar.enter(sym); 4307 } 4308 } 4309 4310 imp.importScope = null; 4311 } 4312 } 4313 4314 /** Check that single-type import is not already imported or top-level defined, 4315 * but make an exception for two single-type imports which denote the same type. 4316 * @param pos Position for error reporting. 4317 * @param ordinallyImportedSoFar A Scope containing types imported so far through 4318 * ordinary imports. 4319 * @param staticallyImportedSoFar A Scope containing types imported so far through 4320 * static imports. 4321 * @param topLevelScope The current file's top-level Scope 4322 * @param sym The symbol. 4323 * @param staticImport Whether or not this was a static import 4324 */ 4325 private boolean checkUniqueImport(DiagnosticPosition pos, Scope ordinallyImportedSoFar, 4326 Scope staticallyImportedSoFar, Scope topLevelScope, 4327 Symbol sym, boolean staticImport) { 4328 Predicate<Symbol> duplicates = candidate -> candidate != sym && !candidate.type.isErroneous(); 4329 Symbol ordinaryClashing = ordinallyImportedSoFar.findFirst(sym.name, duplicates); 4330 Symbol staticClashing = null; 4331 if (ordinaryClashing == null && !staticImport) { 4332 staticClashing = staticallyImportedSoFar.findFirst(sym.name, duplicates); 4333 } 4334 if (ordinaryClashing != null || staticClashing != null) { 4335 if (ordinaryClashing != null) 4336 log.error(pos, Errors.AlreadyDefinedSingleImport(ordinaryClashing)); 4337 else 4338 log.error(pos, Errors.AlreadyDefinedStaticSingleImport(staticClashing)); 4339 return false; 4340 } 4341 Symbol clashing = topLevelScope.findFirst(sym.name, duplicates); 4342 if (clashing != null) { 4343 log.error(pos, Errors.AlreadyDefinedThisUnit(clashing)); 4344 return false; 4345 } 4346 return true; 4347 } 4348 4349 /** Check that a qualified name is in canonical form (for import decls). 4350 */ 4351 public void checkCanonical(JCTree tree) { 4352 if (!isCanonical(tree)) 4353 log.error(tree.pos(), 4354 Errors.ImportRequiresCanonical(TreeInfo.symbol(tree))); 4355 } 4356 // where 4357 private boolean isCanonical(JCTree tree) { 4358 while (tree.hasTag(SELECT)) { 4359 JCFieldAccess s = (JCFieldAccess) tree; 4360 if (s.sym.owner.getQualifiedName() != TreeInfo.symbol(s.selected).getQualifiedName()) 4361 return false; 4362 tree = s.selected; 4363 } 4364 return true; 4365 } 4366 4367 /** Check that an auxiliary class is not accessed from any other file than its own. 4368 */ 4369 void checkForBadAuxiliaryClassAccess(DiagnosticPosition pos, Env<AttrContext> env, ClassSymbol c) { 4370 if (lint.isEnabled(Lint.LintCategory.AUXILIARYCLASS) && 4371 (c.flags() & AUXILIARY) != 0 && 4372 rs.isAccessible(env, c) && 4373 !fileManager.isSameFile(c.sourcefile, env.toplevel.sourcefile)) 4374 { 4375 log.warning(pos, 4376 Warnings.AuxiliaryClassAccessedFromOutsideOfItsSourceFile(c, c.sourcefile)); 4377 } 4378 } 4379 4380 /** 4381 * Check for a default constructor in an exported package. 4382 */ 4383 void checkDefaultConstructor(ClassSymbol c, DiagnosticPosition pos) { 4384 if (lint.isEnabled(LintCategory.MISSING_EXPLICIT_CTOR) && 4385 ((c.flags() & (ENUM | RECORD)) == 0) && 4386 !c.isAnonymous() && 4387 ((c.flags() & (PUBLIC | PROTECTED)) != 0) && 4388 Feature.MODULES.allowedInSource(source)) { 4389 NestingKind nestingKind = c.getNestingKind(); 4390 switch (nestingKind) { 4391 case ANONYMOUS, 4392 LOCAL -> {return;} 4393 case TOP_LEVEL -> {;} // No additional checks needed 4394 case MEMBER -> { 4395 // For nested member classes, all the enclosing 4396 // classes must be public or protected. 4397 Symbol owner = c.owner; 4398 while (owner != null && owner.kind == TYP) { 4399 if ((owner.flags() & (PUBLIC | PROTECTED)) == 0) 4400 return; 4401 owner = owner.owner; 4402 } 4403 } 4404 } 4405 4406 // Only check classes in named packages exported by its module 4407 PackageSymbol pkg = c.packge(); 4408 if (!pkg.isUnnamed()) { 4409 ModuleSymbol modle = pkg.modle; 4410 for (ExportsDirective exportDir : modle.exports) { 4411 // Report warning only if the containing 4412 // package is unconditionally exported 4413 if (exportDir.packge.equals(pkg)) { 4414 if (exportDir.modules == null || exportDir.modules.isEmpty()) { 4415 // Warning may be suppressed by 4416 // annotations; check again for being 4417 // enabled in the deferred context. 4418 deferredLintHandler.report(_l -> { 4419 if (lint.isEnabled(LintCategory.MISSING_EXPLICIT_CTOR)) 4420 log.warning(LintCategory.MISSING_EXPLICIT_CTOR, 4421 pos, Warnings.MissingExplicitCtor(c, pkg, modle)); 4422 }); 4423 } else { 4424 return; 4425 } 4426 } 4427 } 4428 } 4429 } 4430 return; 4431 } 4432 4433 private class ConversionWarner extends Warner { 4434 final String uncheckedKey; 4435 final Type found; 4436 final Type expected; 4437 public ConversionWarner(DiagnosticPosition pos, String uncheckedKey, Type found, Type expected) { 4438 super(pos); 4439 this.uncheckedKey = uncheckedKey; 4440 this.found = found; 4441 this.expected = expected; 4442 } 4443 4444 @Override 4445 public void warn(LintCategory lint) { 4446 boolean warned = this.warned; 4447 super.warn(lint); 4448 if (warned) return; // suppress redundant diagnostics 4449 switch (lint) { 4450 case UNCHECKED: 4451 Check.this.warnUnchecked(pos(), Warnings.ProbFoundReq(diags.fragment(uncheckedKey), found, expected)); 4452 break; 4453 case VARARGS: 4454 if (method != null && 4455 method.attribute(syms.trustMeType.tsym) != null && 4456 isTrustMeAllowedOnMethod(method) && 4457 !types.isReifiable(method.type.getParameterTypes().last())) { 4458 Check.this.warnUnsafeVararg(pos(), Warnings.VarargsUnsafeUseVarargsParam(method.params.last())); 4459 } 4460 break; 4461 default: 4462 throw new AssertionError("Unexpected lint: " + lint); 4463 } 4464 } 4465 } 4466 4467 public Warner castWarner(DiagnosticPosition pos, Type found, Type expected) { 4468 return new ConversionWarner(pos, "unchecked.cast.to.type", found, expected); 4469 } 4470 4471 public Warner convertWarner(DiagnosticPosition pos, Type found, Type expected) { 4472 return new ConversionWarner(pos, "unchecked.assign", found, expected); 4473 } 4474 4475 public void checkFunctionalInterface(JCClassDecl tree, ClassSymbol cs) { 4476 Compound functionalType = cs.attribute(syms.functionalInterfaceType.tsym); 4477 4478 if (functionalType != null) { 4479 try { 4480 types.findDescriptorSymbol((TypeSymbol)cs); 4481 } catch (Types.FunctionDescriptorLookupError ex) { 4482 DiagnosticPosition pos = tree.pos(); 4483 for (JCAnnotation a : tree.getModifiers().annotations) { 4484 if (a.annotationType.type.tsym == syms.functionalInterfaceType.tsym) { 4485 pos = a.pos(); 4486 break; 4487 } 4488 } 4489 log.error(pos, Errors.BadFunctionalIntfAnno1(ex.getDiagnostic())); 4490 } 4491 } 4492 } 4493 4494 public void checkImportsResolvable(final JCCompilationUnit toplevel) { 4495 for (final JCImportBase impBase : toplevel.getImports()) { 4496 if (!(impBase instanceof JCImport imp)) 4497 continue; 4498 if (!imp.staticImport || !imp.qualid.hasTag(SELECT)) 4499 continue; 4500 final JCFieldAccess select = imp.qualid; 4501 final Symbol origin; 4502 if (select.name == names.asterisk || (origin = TreeInfo.symbol(select.selected)) == null || origin.kind != TYP) 4503 continue; 4504 4505 TypeSymbol site = (TypeSymbol) TreeInfo.symbol(select.selected); 4506 if (!checkTypeContainsImportableElement(site, site, toplevel.packge, select.name, new HashSet<Symbol>())) { 4507 log.error(imp.pos(), 4508 Errors.CantResolveLocation(KindName.STATIC, 4509 select.name, 4510 null, 4511 null, 4512 Fragments.Location(kindName(site), 4513 site, 4514 null))); 4515 } 4516 } 4517 } 4518 4519 // Check that packages imported are in scope (JLS 7.4.3, 6.3, 6.5.3.1, 6.5.3.2) 4520 public void checkImportedPackagesObservable(final JCCompilationUnit toplevel) { 4521 OUTER: for (JCImportBase impBase : toplevel.getImports()) { 4522 if (impBase instanceof JCImport imp && !imp.staticImport && 4523 TreeInfo.name(imp.qualid) == names.asterisk) { 4524 TypeSymbol tsym = imp.qualid.selected.type.tsym; 4525 if (tsym.kind == PCK && tsym.members().isEmpty() && 4526 !(Feature.IMPORT_ON_DEMAND_OBSERVABLE_PACKAGES.allowedInSource(source) && tsym.exists())) { 4527 log.error(DiagnosticFlag.RESOLVE_ERROR, imp.qualid.selected.pos(), Errors.DoesntExist(tsym)); 4528 } 4529 } 4530 } 4531 } 4532 4533 private boolean checkTypeContainsImportableElement(TypeSymbol tsym, TypeSymbol origin, PackageSymbol packge, Name name, Set<Symbol> processed) { 4534 if (tsym == null || !processed.add(tsym)) 4535 return false; 4536 4537 // also search through inherited names 4538 if (checkTypeContainsImportableElement(types.supertype(tsym.type).tsym, origin, packge, name, processed)) 4539 return true; 4540 4541 for (Type t : types.interfaces(tsym.type)) 4542 if (checkTypeContainsImportableElement(t.tsym, origin, packge, name, processed)) 4543 return true; 4544 4545 for (Symbol sym : tsym.members().getSymbolsByName(name)) { 4546 if (sym.isStatic() && 4547 importAccessible(sym, packge) && 4548 sym.isMemberOf(origin, types)) { 4549 return true; 4550 } 4551 } 4552 4553 return false; 4554 } 4555 4556 // is the sym accessible everywhere in packge? 4557 public boolean importAccessible(Symbol sym, PackageSymbol packge) { 4558 try { 4559 int flags = (int)(sym.flags() & AccessFlags); 4560 switch (flags) { 4561 default: 4562 case PUBLIC: 4563 return true; 4564 case PRIVATE: 4565 return false; 4566 case 0: 4567 case PROTECTED: 4568 return sym.packge() == packge; 4569 } 4570 } catch (ClassFinder.BadClassFile err) { 4571 throw err; 4572 } catch (CompletionFailure ex) { 4573 return false; 4574 } 4575 } 4576 4577 public void checkLeaksNotAccessible(Env<AttrContext> env, JCClassDecl check) { 4578 JCCompilationUnit toplevel = env.toplevel; 4579 4580 if ( toplevel.modle == syms.unnamedModule 4581 || toplevel.modle == syms.noModule 4582 || (check.sym.flags() & COMPOUND) != 0) { 4583 return ; 4584 } 4585 4586 ExportsDirective currentExport = findExport(toplevel.packge); 4587 4588 if ( currentExport == null //not exported 4589 || currentExport.modules != null) //don't check classes in qualified export 4590 return ; 4591 4592 new TreeScanner() { 4593 Lint lint = env.info.lint; 4594 boolean inSuperType; 4595 4596 @Override 4597 public void visitBlock(JCBlock tree) { 4598 } 4599 @Override 4600 public void visitMethodDef(JCMethodDecl tree) { 4601 if (!isAPISymbol(tree.sym)) 4602 return; 4603 Lint prevLint = lint; 4604 try { 4605 lint = lint.augment(tree.sym); 4606 if (lint.isEnabled(LintCategory.EXPORTS)) { 4607 super.visitMethodDef(tree); 4608 } 4609 } finally { 4610 lint = prevLint; 4611 } 4612 } 4613 @Override 4614 public void visitVarDef(JCVariableDecl tree) { 4615 if (!isAPISymbol(tree.sym) && tree.sym.owner.kind != MTH) 4616 return; 4617 Lint prevLint = lint; 4618 try { 4619 lint = lint.augment(tree.sym); 4620 if (lint.isEnabled(LintCategory.EXPORTS)) { 4621 scan(tree.mods); 4622 scan(tree.vartype); 4623 } 4624 } finally { 4625 lint = prevLint; 4626 } 4627 } 4628 @Override 4629 public void visitClassDef(JCClassDecl tree) { 4630 if (tree != check) 4631 return ; 4632 4633 if (!isAPISymbol(tree.sym)) 4634 return ; 4635 4636 Lint prevLint = lint; 4637 try { 4638 lint = lint.augment(tree.sym); 4639 if (lint.isEnabled(LintCategory.EXPORTS)) { 4640 scan(tree.mods); 4641 scan(tree.typarams); 4642 try { 4643 inSuperType = true; 4644 scan(tree.extending); 4645 scan(tree.implementing); 4646 } finally { 4647 inSuperType = false; 4648 } 4649 scan(tree.defs); 4650 } 4651 } finally { 4652 lint = prevLint; 4653 } 4654 } 4655 @Override 4656 public void visitTypeApply(JCTypeApply tree) { 4657 scan(tree.clazz); 4658 boolean oldInSuperType = inSuperType; 4659 try { 4660 inSuperType = false; 4661 scan(tree.arguments); 4662 } finally { 4663 inSuperType = oldInSuperType; 4664 } 4665 } 4666 @Override 4667 public void visitIdent(JCIdent tree) { 4668 Symbol sym = TreeInfo.symbol(tree); 4669 if (sym.kind == TYP && !sym.type.hasTag(TYPEVAR)) { 4670 checkVisible(tree.pos(), sym, toplevel.packge, inSuperType); 4671 } 4672 } 4673 4674 @Override 4675 public void visitSelect(JCFieldAccess tree) { 4676 Symbol sym = TreeInfo.symbol(tree); 4677 Symbol sitesym = TreeInfo.symbol(tree.selected); 4678 if (sym.kind == TYP && sitesym.kind == PCK) { 4679 checkVisible(tree.pos(), sym, toplevel.packge, inSuperType); 4680 } else { 4681 super.visitSelect(tree); 4682 } 4683 } 4684 4685 @Override 4686 public void visitAnnotation(JCAnnotation tree) { 4687 if (tree.attribute.type.tsym.getAnnotation(java.lang.annotation.Documented.class) != null) 4688 super.visitAnnotation(tree); 4689 } 4690 4691 }.scan(check); 4692 } 4693 //where: 4694 private ExportsDirective findExport(PackageSymbol pack) { 4695 for (ExportsDirective d : pack.modle.exports) { 4696 if (d.packge == pack) 4697 return d; 4698 } 4699 4700 return null; 4701 } 4702 private boolean isAPISymbol(Symbol sym) { 4703 while (sym.kind != PCK) { 4704 if ((sym.flags() & Flags.PUBLIC) == 0 && (sym.flags() & Flags.PROTECTED) == 0) { 4705 return false; 4706 } 4707 sym = sym.owner; 4708 } 4709 return true; 4710 } 4711 private void checkVisible(DiagnosticPosition pos, Symbol what, PackageSymbol inPackage, boolean inSuperType) { 4712 if (!isAPISymbol(what) && !inSuperType) { //package private/private element 4713 log.warning(LintCategory.EXPORTS, pos, Warnings.LeaksNotAccessible(kindName(what), what, what.packge().modle)); 4714 return ; 4715 } 4716 4717 PackageSymbol whatPackage = what.packge(); 4718 ExportsDirective whatExport = findExport(whatPackage); 4719 ExportsDirective inExport = findExport(inPackage); 4720 4721 if (whatExport == null) { //package not exported: 4722 log.warning(LintCategory.EXPORTS, pos, Warnings.LeaksNotAccessibleUnexported(kindName(what), what, what.packge().modle)); 4723 return ; 4724 } 4725 4726 if (whatExport.modules != null) { 4727 if (inExport.modules == null || !whatExport.modules.containsAll(inExport.modules)) { 4728 log.warning(LintCategory.EXPORTS, pos, Warnings.LeaksNotAccessibleUnexportedQualified(kindName(what), what, what.packge().modle)); 4729 } 4730 } 4731 4732 if (whatPackage.modle != inPackage.modle && whatPackage.modle != syms.java_base) { 4733 //check that relativeTo.modle requires transitive what.modle, somehow: 4734 List<ModuleSymbol> todo = List.of(inPackage.modle); 4735 4736 while (todo.nonEmpty()) { 4737 ModuleSymbol current = todo.head; 4738 todo = todo.tail; 4739 if (current == whatPackage.modle) 4740 return ; //OK 4741 if ((current.flags() & Flags.AUTOMATIC_MODULE) != 0) 4742 continue; //for automatic modules, don't look into their dependencies 4743 for (RequiresDirective req : current.requires) { 4744 if (req.isTransitive()) { 4745 todo = todo.prepend(req.module); 4746 } 4747 } 4748 } 4749 4750 log.warning(LintCategory.EXPORTS, pos, Warnings.LeaksNotAccessibleNotRequiredTransitive(kindName(what), what, what.packge().modle)); 4751 } 4752 } 4753 4754 void checkModuleExists(final DiagnosticPosition pos, ModuleSymbol msym) { 4755 if (msym.kind != MDL) { 4756 deferredLintHandler.report(_l -> { 4757 if (lint.isEnabled(LintCategory.MODULE)) 4758 log.warning(LintCategory.MODULE, pos, Warnings.ModuleNotFound(msym)); 4759 }); 4760 } 4761 } 4762 4763 void checkPackageExistsForOpens(final DiagnosticPosition pos, PackageSymbol packge) { 4764 if (packge.members().isEmpty() && 4765 ((packge.flags() & Flags.HAS_RESOURCE) == 0)) { 4766 deferredLintHandler.report(_l -> { 4767 if (lint.isEnabled(LintCategory.OPENS)) 4768 log.warning(pos, Warnings.PackageEmptyOrNotFound(packge)); 4769 }); 4770 } 4771 } 4772 4773 void checkModuleRequires(final DiagnosticPosition pos, final RequiresDirective rd) { 4774 if ((rd.module.flags() & Flags.AUTOMATIC_MODULE) != 0) { 4775 deferredLintHandler.report(_l -> { 4776 if (rd.isTransitive() && lint.isEnabled(LintCategory.REQUIRES_TRANSITIVE_AUTOMATIC)) { 4777 log.warning(pos, Warnings.RequiresTransitiveAutomatic); 4778 } else if (lint.isEnabled(LintCategory.REQUIRES_AUTOMATIC)) { 4779 log.warning(pos, Warnings.RequiresAutomatic); 4780 } 4781 }); 4782 } 4783 } 4784 4785 /** 4786 * Verify the case labels conform to the constraints. Checks constraints related 4787 * combinations of patterns and other labels. 4788 * 4789 * @param cases the cases that should be checked. 4790 */ 4791 void checkSwitchCaseStructure(List<JCCase> cases) { 4792 for (List<JCCase> l = cases; l.nonEmpty(); l = l.tail) { 4793 JCCase c = l.head; 4794 if (c.labels.head instanceof JCConstantCaseLabel constLabel) { 4795 if (TreeInfo.isNull(constLabel.expr)) { 4796 if (c.labels.tail.nonEmpty()) { 4797 if (c.labels.tail.head instanceof JCDefaultCaseLabel defLabel) { 4798 if (c.labels.tail.tail.nonEmpty()) { 4799 log.error(c.labels.tail.tail.head.pos(), Errors.InvalidCaseLabelCombination); 4800 } 4801 } else { 4802 log.error(c.labels.tail.head.pos(), Errors.InvalidCaseLabelCombination); 4803 } 4804 } 4805 } else { 4806 for (JCCaseLabel label : c.labels.tail) { 4807 if (!(label instanceof JCConstantCaseLabel) || TreeInfo.isNullCaseLabel(label)) { 4808 log.error(label.pos(), Errors.InvalidCaseLabelCombination); 4809 break; 4810 } 4811 } 4812 } 4813 } else if (c.labels.tail.nonEmpty()) { 4814 var patterCaseLabels = c.labels.stream().filter(ll -> ll instanceof JCPatternCaseLabel).map(cl -> (JCPatternCaseLabel)cl); 4815 var allUnderscore = patterCaseLabels.allMatch(pcl -> !hasBindings(pcl.getPattern())); 4816 4817 if (!allUnderscore) { 4818 log.error(c.labels.tail.head.pos(), Errors.FlowsThroughFromPattern); 4819 } 4820 4821 boolean allPatternCaseLabels = c.labels.stream().allMatch(p -> p instanceof JCPatternCaseLabel); 4822 4823 if (allPatternCaseLabels) { 4824 preview.checkSourceLevel(c.labels.tail.head.pos(), Feature.UNNAMED_VARIABLES); 4825 } 4826 4827 for (JCCaseLabel label : c.labels.tail) { 4828 if (label instanceof JCConstantCaseLabel) { 4829 log.error(label.pos(), Errors.InvalidCaseLabelCombination); 4830 break; 4831 } 4832 } 4833 } 4834 } 4835 4836 boolean isCaseStatementGroup = cases.nonEmpty() && 4837 cases.head.caseKind == CaseTree.CaseKind.STATEMENT; 4838 4839 if (isCaseStatementGroup) { 4840 boolean previousCompletessNormally = false; 4841 for (List<JCCase> l = cases; l.nonEmpty(); l = l.tail) { 4842 JCCase c = l.head; 4843 if (previousCompletessNormally && 4844 c.stats.nonEmpty() && 4845 c.labels.head instanceof JCPatternCaseLabel patternLabel && 4846 (hasBindings(patternLabel.pat) || hasBindings(c.guard))) { 4847 log.error(c.labels.head.pos(), Errors.FlowsThroughToPattern); 4848 } else if (c.stats.isEmpty() && 4849 c.labels.head instanceof JCPatternCaseLabel patternLabel && 4850 (hasBindings(patternLabel.pat) || hasBindings(c.guard)) && 4851 hasStatements(l.tail)) { 4852 log.error(c.labels.head.pos(), Errors.FlowsThroughFromPattern); 4853 } 4854 previousCompletessNormally = c.completesNormally; 4855 } 4856 } 4857 } 4858 4859 boolean hasBindings(JCTree p) { 4860 boolean[] bindings = new boolean[1]; 4861 4862 new TreeScanner() { 4863 @Override 4864 public void visitBindingPattern(JCBindingPattern tree) { 4865 bindings[0] = !tree.var.sym.isUnnamedVariable(); 4866 super.visitBindingPattern(tree); 4867 } 4868 }.scan(p); 4869 4870 return bindings[0]; 4871 } 4872 4873 boolean hasStatements(List<JCCase> cases) { 4874 for (List<JCCase> l = cases; l.nonEmpty(); l = l.tail) { 4875 if (l.head.stats.nonEmpty()) { 4876 return true; 4877 } 4878 } 4879 4880 return false; 4881 } 4882 void checkSwitchCaseLabelDominated(JCCaseLabel unconditionalCaseLabel, List<JCCase> cases) { 4883 List<Pair<JCCase, JCCaseLabel>> caseLabels = List.nil(); 4884 boolean seenDefault = false; 4885 boolean seenDefaultLabel = false; 4886 boolean warnDominatedByDefault = false; 4887 boolean unconditionalFound = false; 4888 4889 for (List<JCCase> l = cases; l.nonEmpty(); l = l.tail) { 4890 JCCase c = l.head; 4891 for (JCCaseLabel label : c.labels) { 4892 if (label.hasTag(DEFAULTCASELABEL)) { 4893 seenDefault = true; 4894 seenDefaultLabel |= 4895 TreeInfo.isNullCaseLabel(c.labels.head); 4896 continue; 4897 } 4898 if (TreeInfo.isNullCaseLabel(label)) { 4899 if (seenDefault) { 4900 log.error(label.pos(), Errors.PatternDominated); 4901 } 4902 continue; 4903 } 4904 if (seenDefault && !warnDominatedByDefault) { 4905 if (label.hasTag(PATTERNCASELABEL) || 4906 (label instanceof JCConstantCaseLabel && seenDefaultLabel)) { 4907 log.error(label.pos(), Errors.PatternDominated); 4908 warnDominatedByDefault = true; 4909 } 4910 } 4911 Type currentType = labelType(label); 4912 for (Pair<JCCase, JCCaseLabel> caseAndLabel : caseLabels) { 4913 JCCase testCase = caseAndLabel.fst; 4914 JCCaseLabel testCaseLabel = caseAndLabel.snd; 4915 Type testType = labelType(testCaseLabel); 4916 boolean dominated = false; 4917 if (types.isUnconditionallyExact(currentType, testType) && 4918 !currentType.hasTag(ERROR) && !testType.hasTag(ERROR)) { 4919 //the current label is potentially dominated by the existing (test) label, check: 4920 if (label instanceof JCConstantCaseLabel) { 4921 dominated |= !(testCaseLabel instanceof JCConstantCaseLabel) && 4922 TreeInfo.unguardedCase(testCase); 4923 } else if (label instanceof JCPatternCaseLabel patternCL && 4924 testCaseLabel instanceof JCPatternCaseLabel testPatternCaseLabel && 4925 (testCase.equals(c) || TreeInfo.unguardedCase(testCase))) { 4926 dominated = patternDominated(testPatternCaseLabel.pat, 4927 patternCL.pat); 4928 } 4929 } 4930 4931 if (dominated) { 4932 log.error(label.pos(), Errors.PatternDominated); 4933 } 4934 } 4935 caseLabels = caseLabels.prepend(Pair.of(c, label)); 4936 } 4937 } 4938 } 4939 //where: 4940 private Type labelType(JCCaseLabel label) { 4941 return types.erasure(switch (label.getTag()) { 4942 case PATTERNCASELABEL -> ((JCPatternCaseLabel) label).pat.type; 4943 case CONSTANTCASELABEL -> ((JCConstantCaseLabel) label).expr.type; 4944 default -> throw Assert.error("Unexpected tree kind: " + label.getTag()); 4945 }); 4946 } 4947 private boolean patternDominated(JCPattern existingPattern, JCPattern currentPattern) { 4948 Type existingPatternType = types.erasure(existingPattern.type); 4949 Type currentPatternType = types.erasure(currentPattern.type); 4950 if (!types.isUnconditionallyExact(currentPatternType, existingPatternType)) { 4951 return false; 4952 } 4953 if (currentPattern instanceof JCBindingPattern || 4954 currentPattern instanceof JCAnyPattern) { 4955 return existingPattern instanceof JCBindingPattern || 4956 existingPattern instanceof JCAnyPattern; 4957 } else if (currentPattern instanceof JCRecordPattern currentRecordPattern) { 4958 if (existingPattern instanceof JCBindingPattern || 4959 existingPattern instanceof JCAnyPattern) { 4960 return true; 4961 } else if (existingPattern instanceof JCRecordPattern existingRecordPattern) { 4962 List<JCPattern> existingNested = existingRecordPattern.nested; 4963 List<JCPattern> currentNested = currentRecordPattern.nested; 4964 if (existingNested.size() != currentNested.size()) { 4965 return false; 4966 } 4967 while (existingNested.nonEmpty()) { 4968 if (!patternDominated(existingNested.head, currentNested.head)) { 4969 return false; 4970 } 4971 existingNested = existingNested.tail; 4972 currentNested = currentNested.tail; 4973 } 4974 return true; 4975 } else { 4976 Assert.error("Unknown pattern: " + existingPattern.getTag()); 4977 } 4978 } else { 4979 Assert.error("Unknown pattern: " + currentPattern.getTag()); 4980 } 4981 return false; 4982 } 4983 4984 /** check if a type is a subtype of Externalizable, if that is available. */ 4985 boolean isExternalizable(Type t) { 4986 try { 4987 syms.externalizableType.complete(); 4988 } catch (CompletionFailure e) { 4989 return false; 4990 } 4991 return types.isSubtype(t, syms.externalizableType); 4992 } 4993 4994 /** 4995 * Check structure of serialization declarations. 4996 */ 4997 public void checkSerialStructure(Env<AttrContext> env, JCClassDecl tree, ClassSymbol c) { 4998 (new SerialTypeVisitor(env)).visit(c, tree); 4999 } 5000 5001 /** 5002 * This visitor will warn if a serialization-related field or 5003 * method is declared in a suspicious or incorrect way. In 5004 * particular, it will warn for cases where the runtime 5005 * serialization mechanism will silently ignore a mis-declared 5006 * entity. 5007 * 5008 * Distinguished serialization-related fields and methods: 5009 * 5010 * Methods: 5011 * 5012 * private void writeObject(ObjectOutputStream stream) throws IOException 5013 * ANY-ACCESS-MODIFIER Object writeReplace() throws ObjectStreamException 5014 * 5015 * private void readObject(ObjectInputStream stream) throws IOException, ClassNotFoundException 5016 * private void readObjectNoData() throws ObjectStreamException 5017 * ANY-ACCESS-MODIFIER Object readResolve() throws ObjectStreamException 5018 * 5019 * Fields: 5020 * 5021 * private static final long serialVersionUID 5022 * private static final ObjectStreamField[] serialPersistentFields 5023 * 5024 * Externalizable: methods defined on the interface 5025 * public void writeExternal(ObjectOutput) throws IOException 5026 * public void readExternal(ObjectInput) throws IOException 5027 */ 5028 private class SerialTypeVisitor extends ElementKindVisitor14<Void, JCClassDecl> { 5029 Env<AttrContext> env; 5030 SerialTypeVisitor(Env<AttrContext> env) { 5031 this.lint = Check.this.lint; 5032 this.env = env; 5033 } 5034 5035 private static final Set<String> serialMethodNames = 5036 Set.of("writeObject", "writeReplace", 5037 "readObject", "readObjectNoData", 5038 "readResolve"); 5039 5040 private static final Set<String> serialFieldNames = 5041 Set.of("serialVersionUID", "serialPersistentFields"); 5042 5043 // Type of serialPersistentFields 5044 private final Type OSF_TYPE = new Type.ArrayType(syms.objectStreamFieldType, syms.arrayClass); 5045 5046 Lint lint; 5047 5048 @Override 5049 public Void defaultAction(Element e, JCClassDecl p) { 5050 throw new IllegalArgumentException(Objects.requireNonNullElse(e.toString(), "")); 5051 } 5052 5053 @Override 5054 public Void visitType(TypeElement e, JCClassDecl p) { 5055 runUnderLint(e, p, (symbol, param) -> super.visitType(symbol, param)); 5056 return null; 5057 } 5058 5059 @Override 5060 public Void visitTypeAsClass(TypeElement e, 5061 JCClassDecl p) { 5062 // Anonymous classes filtered out by caller. 5063 5064 ClassSymbol c = (ClassSymbol)e; 5065 5066 checkCtorAccess(p, c); 5067 5068 // Check for missing serialVersionUID; check *not* done 5069 // for enums or records. 5070 VarSymbol svuidSym = null; 5071 for (Symbol sym : c.members().getSymbolsByName(names.serialVersionUID)) { 5072 if (sym.kind == VAR) { 5073 svuidSym = (VarSymbol)sym; 5074 break; 5075 } 5076 } 5077 5078 if (svuidSym == null) { 5079 log.warning(LintCategory.SERIAL, p.pos(), Warnings.MissingSVUID(c)); 5080 } 5081 5082 // Check for serialPersistentFields to gate checks for 5083 // non-serializable non-transient instance fields 5084 boolean serialPersistentFieldsPresent = 5085 c.members() 5086 .getSymbolsByName(names.serialPersistentFields, sym -> sym.kind == VAR) 5087 .iterator() 5088 .hasNext(); 5089 5090 // Check declarations of serialization-related methods and 5091 // fields 5092 final boolean[] hasWriteReplace = {false}; 5093 for(Symbol el : c.getEnclosedElements()) { 5094 runUnderLint(el, p, (enclosed, tree) -> { 5095 String name = null; 5096 switch(enclosed.getKind()) { 5097 case FIELD -> { 5098 if (!serialPersistentFieldsPresent) { 5099 var flags = enclosed.flags(); 5100 if ( ((flags & TRANSIENT) == 0) && 5101 ((flags & STATIC) == 0)) { 5102 Type varType = enclosed.asType(); 5103 if (!canBeSerialized(varType)) { 5104 // Note per JLS arrays are 5105 // serializable even if the 5106 // component type is not. 5107 log.warning(LintCategory.SERIAL, 5108 TreeInfo.diagnosticPositionFor(enclosed, tree), 5109 Warnings.NonSerializableInstanceField); 5110 } else if (varType.hasTag(ARRAY)) { 5111 ArrayType arrayType = (ArrayType)varType; 5112 Type elementType = arrayType.elemtype; 5113 while (elementType.hasTag(ARRAY)) { 5114 arrayType = (ArrayType)elementType; 5115 elementType = arrayType.elemtype; 5116 } 5117 if (!canBeSerialized(elementType)) { 5118 log.warning(LintCategory.SERIAL, 5119 TreeInfo.diagnosticPositionFor(enclosed, tree), 5120 Warnings.NonSerializableInstanceFieldArray(elementType)); 5121 } 5122 } 5123 } 5124 } 5125 5126 name = enclosed.getSimpleName().toString(); 5127 if (serialFieldNames.contains(name)) { 5128 VarSymbol field = (VarSymbol)enclosed; 5129 switch (name) { 5130 case "serialVersionUID" -> checkSerialVersionUID(tree, e, field); 5131 case "serialPersistentFields" -> checkSerialPersistentFields(tree, e, field); 5132 default -> throw new AssertionError(); 5133 } 5134 } 5135 } 5136 5137 // Correctly checking the serialization-related 5138 // methods is subtle. For the methods declared to be 5139 // private or directly declared in the class, the 5140 // enclosed elements of the class can be checked in 5141 // turn. However, writeReplace and readResolve can be 5142 // declared in a superclass and inherited. Note that 5143 // the runtime lookup walks the superclass chain 5144 // looking for writeReplace/readResolve via 5145 // Class.getDeclaredMethod. This differs from calling 5146 // Elements.getAllMembers(TypeElement) as the latter 5147 // will also pull in default methods from 5148 // superinterfaces. In other words, the runtime checks 5149 // (which long predate default methods on interfaces) 5150 // do not admit the possibility of inheriting methods 5151 // this way, a difference from general inheritance. 5152 5153 // The current implementation just checks the enclosed 5154 // elements and does not directly check the inherited 5155 // methods. If all the types are being checked this is 5156 // less of a concern; however, there are cases that 5157 // could be missed. In particular, readResolve and 5158 // writeReplace could, in principle, by inherited from 5159 // a non-serializable superclass and thus not checked 5160 // even if compiled with a serializable child class. 5161 case METHOD -> { 5162 var method = (MethodSymbol)enclosed; 5163 name = method.getSimpleName().toString(); 5164 if (serialMethodNames.contains(name)) { 5165 switch (name) { 5166 case "writeObject" -> checkWriteObject(tree, e, method); 5167 case "writeReplace" -> {hasWriteReplace[0] = true; hasAppropriateWriteReplace(tree, method, true);} 5168 case "readObject" -> checkReadObject(tree,e, method); 5169 case "readObjectNoData" -> checkReadObjectNoData(tree, e, method); 5170 case "readResolve" -> checkReadResolve(tree, e, method); 5171 default -> throw new AssertionError(); 5172 } 5173 } 5174 } 5175 } 5176 }); 5177 } 5178 if (!hasWriteReplace[0] && 5179 (c.isValueClass() || hasAbstractValueSuperClass(c, Set.of(syms.numberType.tsym))) && 5180 !c.isAbstract() && !c.isRecord() && 5181 types.unboxedType(c.type) == Type.noType) { 5182 // we need to check if the class is inheriting an appropriate writeReplace method 5183 MethodSymbol ms = null; 5184 Log.DiagnosticHandler discardHandler = new Log.DiscardDiagnosticHandler(log); 5185 try { 5186 ms = rs.resolveInternalMethod(env.tree, env, c.type, names.writeReplace, List.nil(), List.nil()); 5187 } catch (FatalError fe) { 5188 // ignore no method was found 5189 } finally { 5190 log.popDiagnosticHandler(discardHandler); 5191 } 5192 if (ms == null || !hasAppropriateWriteReplace(p, ms, false)) { 5193 log.warning(LintCategory.SERIAL, p, 5194 c.isValueClass() ? Warnings.SerializableValueClassWithoutWriteReplace1 : 5195 Warnings.SerializableValueClassWithoutWriteReplace2); 5196 } 5197 } 5198 return null; 5199 } 5200 5201 boolean canBeSerialized(Type type) { 5202 return type.isPrimitive() || rs.isSerializable(type); 5203 } 5204 5205 private boolean hasAbstractValueSuperClass(Symbol c, Set<Symbol> excluding) { 5206 while (c.getKind() == ElementKind.CLASS) { 5207 Type sup = ((ClassSymbol)c).getSuperclass(); 5208 if (!sup.hasTag(CLASS) || sup.isErroneous() || 5209 sup.tsym == syms.objectType.tsym) { 5210 return false; 5211 } 5212 // if it is a value super class it has to be abstract 5213 if (sup.isValueClass() && !excluding.contains(sup.tsym)) { 5214 return true; 5215 } 5216 c = sup.tsym; 5217 } 5218 return false; 5219 } 5220 5221 /** 5222 * Check that Externalizable class needs a public no-arg 5223 * constructor. 5224 * 5225 * Check that a Serializable class has access to the no-arg 5226 * constructor of its first nonserializable superclass. 5227 */ 5228 private void checkCtorAccess(JCClassDecl tree, ClassSymbol c) { 5229 if (isExternalizable(c.type)) { 5230 for(var sym : c.getEnclosedElements()) { 5231 if (sym.isConstructor() && 5232 ((sym.flags() & PUBLIC) == PUBLIC)) { 5233 if (((MethodSymbol)sym).getParameters().isEmpty()) { 5234 return; 5235 } 5236 } 5237 } 5238 log.warning(LintCategory.SERIAL, tree.pos(), 5239 Warnings.ExternalizableMissingPublicNoArgCtor); 5240 } else { 5241 // Approximate access to the no-arg constructor up in 5242 // the superclass chain by checking that the 5243 // constructor is not private. This may not handle 5244 // some cross-package situations correctly. 5245 Type superClass = c.getSuperclass(); 5246 // java.lang.Object is *not* Serializable so this loop 5247 // should terminate. 5248 while (rs.isSerializable(superClass) ) { 5249 try { 5250 superClass = (Type)((TypeElement)(((DeclaredType)superClass)).asElement()).getSuperclass(); 5251 } catch(ClassCastException cce) { 5252 return ; // Don't try to recover 5253 } 5254 } 5255 // Non-Serializable superclass 5256 try { 5257 ClassSymbol supertype = ((ClassSymbol)(((DeclaredType)superClass).asElement())); 5258 for(var sym : supertype.getEnclosedElements()) { 5259 if (sym.isConstructor()) { 5260 MethodSymbol ctor = (MethodSymbol)sym; 5261 if (ctor.getParameters().isEmpty()) { 5262 if (((ctor.flags() & PRIVATE) == PRIVATE) || 5263 // Handle nested classes and implicit this$0 5264 (supertype.getNestingKind() == NestingKind.MEMBER && 5265 ((supertype.flags() & STATIC) == 0))) 5266 log.warning(LintCategory.SERIAL, tree.pos(), 5267 Warnings.SerializableMissingAccessNoArgCtor(supertype.getQualifiedName())); 5268 } 5269 } 5270 } 5271 } catch (ClassCastException cce) { 5272 return ; // Don't try to recover 5273 } 5274 return; 5275 } 5276 } 5277 5278 private void checkSerialVersionUID(JCClassDecl tree, Element e, VarSymbol svuid) { 5279 // To be effective, serialVersionUID must be marked static 5280 // and final, but private is recommended. But alas, in 5281 // practice there are many non-private serialVersionUID 5282 // fields. 5283 if ((svuid.flags() & (STATIC | FINAL)) != 5284 (STATIC | FINAL)) { 5285 log.warning(LintCategory.SERIAL, 5286 TreeInfo.diagnosticPositionFor(svuid, tree), 5287 Warnings.ImproperSVUID((Symbol)e)); 5288 } 5289 5290 // check svuid has type long 5291 if (!svuid.type.hasTag(LONG)) { 5292 log.warning(LintCategory.SERIAL, 5293 TreeInfo.diagnosticPositionFor(svuid, tree), 5294 Warnings.LongSVUID((Symbol)e)); 5295 } 5296 5297 if (svuid.getConstValue() == null) 5298 log.warning(LintCategory.SERIAL, 5299 TreeInfo.diagnosticPositionFor(svuid, tree), 5300 Warnings.ConstantSVUID((Symbol)e)); 5301 } 5302 5303 private void checkSerialPersistentFields(JCClassDecl tree, Element e, VarSymbol spf) { 5304 // To be effective, serialPersisentFields must be private, static, and final. 5305 if ((spf.flags() & (PRIVATE | STATIC | FINAL)) != 5306 (PRIVATE | STATIC | FINAL)) { 5307 log.warning(LintCategory.SERIAL, 5308 TreeInfo.diagnosticPositionFor(spf, tree), 5309 Warnings.ImproperSPF); 5310 } 5311 5312 if (!types.isSameType(spf.type, OSF_TYPE)) { 5313 log.warning(LintCategory.SERIAL, 5314 TreeInfo.diagnosticPositionFor(spf, tree), 5315 Warnings.OSFArraySPF); 5316 } 5317 5318 if (isExternalizable((Type)(e.asType()))) { 5319 log.warning(LintCategory.SERIAL, 5320 TreeInfo.diagnosticPositionFor(spf, tree), 5321 Warnings.IneffectualSerialFieldExternalizable); 5322 } 5323 5324 // Warn if serialPersistentFields is initialized to a 5325 // literal null. 5326 JCTree spfDecl = TreeInfo.declarationFor(spf, tree); 5327 if (spfDecl != null && spfDecl.getTag() == VARDEF) { 5328 JCVariableDecl variableDef = (JCVariableDecl) spfDecl; 5329 JCExpression initExpr = variableDef.init; 5330 if (initExpr != null && TreeInfo.isNull(initExpr)) { 5331 log.warning(LintCategory.SERIAL, initExpr.pos(), 5332 Warnings.SPFNullInit); 5333 } 5334 } 5335 } 5336 5337 private void checkWriteObject(JCClassDecl tree, Element e, MethodSymbol method) { 5338 // The "synchronized" modifier is seen in the wild on 5339 // readObject and writeObject methods and is generally 5340 // innocuous. 5341 5342 // private void writeObject(ObjectOutputStream stream) throws IOException 5343 checkPrivateNonStaticMethod(tree, method); 5344 isExpectedReturnType(tree, method, syms.voidType, true); 5345 checkOneArg(tree, e, method, syms.objectOutputStreamType); 5346 hasExpectedExceptions(tree, method, true, syms.ioExceptionType); 5347 checkExternalizable(tree, e, method); 5348 } 5349 5350 private boolean hasAppropriateWriteReplace(JCClassDecl tree, MethodSymbol method, boolean warn) { 5351 // ANY-ACCESS-MODIFIER Object writeReplace() throws 5352 // ObjectStreamException 5353 5354 // Excluding abstract, could have a more complicated 5355 // rule based on abstract-ness of the class 5356 return isConcreteInstanceMethod(tree, method, warn) && 5357 isExpectedReturnType(tree, method, syms.objectType, warn) && 5358 hasNoArgs(tree, method, warn) && 5359 hasExpectedExceptions(tree, method, warn, syms.objectStreamExceptionType); 5360 } 5361 5362 private void checkReadObject(JCClassDecl tree, Element e, MethodSymbol method) { 5363 // The "synchronized" modifier is seen in the wild on 5364 // readObject and writeObject methods and is generally 5365 // innocuous. 5366 5367 // private void readObject(ObjectInputStream stream) 5368 // throws IOException, ClassNotFoundException 5369 checkPrivateNonStaticMethod(tree, method); 5370 isExpectedReturnType(tree, method, syms.voidType, true); 5371 checkOneArg(tree, e, method, syms.objectInputStreamType); 5372 hasExpectedExceptions(tree, method, true, syms.ioExceptionType, syms.classNotFoundExceptionType); 5373 checkExternalizable(tree, e, method); 5374 } 5375 5376 private void checkReadObjectNoData(JCClassDecl tree, Element e, MethodSymbol method) { 5377 // private void readObjectNoData() throws ObjectStreamException 5378 checkPrivateNonStaticMethod(tree, method); 5379 isExpectedReturnType(tree, method, syms.voidType, true); 5380 hasNoArgs(tree, method, true); 5381 hasExpectedExceptions(tree, method, true, syms.objectStreamExceptionType); 5382 checkExternalizable(tree, e, method); 5383 } 5384 5385 private void checkReadResolve(JCClassDecl tree, Element e, MethodSymbol method) { 5386 // ANY-ACCESS-MODIFIER Object readResolve() 5387 // throws ObjectStreamException 5388 5389 // Excluding abstract, could have a more complicated 5390 // rule based on abstract-ness of the class 5391 isConcreteInstanceMethod(tree, method, true); 5392 isExpectedReturnType(tree, method, syms.objectType, true); 5393 hasNoArgs(tree, method, true); 5394 hasExpectedExceptions(tree, method, true, syms.objectStreamExceptionType); 5395 } 5396 5397 private void checkWriteExternalRecord(JCClassDecl tree, Element e, MethodSymbol method, boolean isExtern) { 5398 //public void writeExternal(ObjectOutput) throws IOException 5399 checkExternMethodRecord(tree, e, method, syms.objectOutputType, isExtern); 5400 } 5401 5402 private void checkReadExternalRecord(JCClassDecl tree, Element e, MethodSymbol method, boolean isExtern) { 5403 // public void readExternal(ObjectInput) throws IOException 5404 checkExternMethodRecord(tree, e, method, syms.objectInputType, isExtern); 5405 } 5406 5407 private void checkExternMethodRecord(JCClassDecl tree, Element e, MethodSymbol method, Type argType, 5408 boolean isExtern) { 5409 if (isExtern && isExternMethod(tree, e, method, argType)) { 5410 log.warning(LintCategory.SERIAL, 5411 TreeInfo.diagnosticPositionFor(method, tree), 5412 Warnings.IneffectualExternalizableMethodRecord(method.getSimpleName().toString())); 5413 } 5414 } 5415 5416 void checkPrivateNonStaticMethod(JCClassDecl tree, MethodSymbol method) { 5417 var flags = method.flags(); 5418 if ((flags & PRIVATE) == 0) { 5419 log.warning(LintCategory.SERIAL, 5420 TreeInfo.diagnosticPositionFor(method, tree), 5421 Warnings.SerialMethodNotPrivate(method.getSimpleName())); 5422 } 5423 5424 if ((flags & STATIC) != 0) { 5425 log.warning(LintCategory.SERIAL, 5426 TreeInfo.diagnosticPositionFor(method, tree), 5427 Warnings.SerialMethodStatic(method.getSimpleName())); 5428 } 5429 } 5430 5431 /** 5432 * Per section 1.12 "Serialization of Enum Constants" of 5433 * the serialization specification, due to the special 5434 * serialization handling of enums, any writeObject, 5435 * readObject, writeReplace, and readResolve methods are 5436 * ignored as are serialPersistentFields and 5437 * serialVersionUID fields. 5438 */ 5439 @Override 5440 public Void visitTypeAsEnum(TypeElement e, 5441 JCClassDecl p) { 5442 boolean isExtern = isExternalizable((Type)e.asType()); 5443 for(Element el : e.getEnclosedElements()) { 5444 runUnderLint(el, p, (enclosed, tree) -> { 5445 String name = enclosed.getSimpleName().toString(); 5446 switch(enclosed.getKind()) { 5447 case FIELD -> { 5448 var field = (VarSymbol)enclosed; 5449 if (serialFieldNames.contains(name)) { 5450 log.warning(LintCategory.SERIAL, 5451 TreeInfo.diagnosticPositionFor(field, tree), 5452 Warnings.IneffectualSerialFieldEnum(name)); 5453 } 5454 } 5455 5456 case METHOD -> { 5457 var method = (MethodSymbol)enclosed; 5458 if (serialMethodNames.contains(name)) { 5459 log.warning(LintCategory.SERIAL, 5460 TreeInfo.diagnosticPositionFor(method, tree), 5461 Warnings.IneffectualSerialMethodEnum(name)); 5462 } 5463 5464 if (isExtern) { 5465 switch(name) { 5466 case "writeExternal" -> checkWriteExternalEnum(tree, e, method); 5467 case "readExternal" -> checkReadExternalEnum(tree, e, method); 5468 } 5469 } 5470 } 5471 5472 // Also perform checks on any class bodies of enum constants, see JLS 8.9.1. 5473 case ENUM_CONSTANT -> { 5474 var field = (VarSymbol)enclosed; 5475 JCVariableDecl decl = (JCVariableDecl) TreeInfo.declarationFor(field, p); 5476 if (decl.init instanceof JCNewClass nc && nc.def != null) { 5477 ClassSymbol enumConstantType = nc.def.sym; 5478 visitTypeAsEnum(enumConstantType, p); 5479 } 5480 } 5481 5482 }}); 5483 } 5484 return null; 5485 } 5486 5487 private void checkWriteExternalEnum(JCClassDecl tree, Element e, MethodSymbol method) { 5488 //public void writeExternal(ObjectOutput) throws IOException 5489 checkExternMethodEnum(tree, e, method, syms.objectOutputType); 5490 } 5491 5492 private void checkReadExternalEnum(JCClassDecl tree, Element e, MethodSymbol method) { 5493 // public void readExternal(ObjectInput) throws IOException 5494 checkExternMethodEnum(tree, e, method, syms.objectInputType); 5495 } 5496 5497 private void checkExternMethodEnum(JCClassDecl tree, Element e, MethodSymbol method, Type argType) { 5498 if (isExternMethod(tree, e, method, argType)) { 5499 log.warning(LintCategory.SERIAL, 5500 TreeInfo.diagnosticPositionFor(method, tree), 5501 Warnings.IneffectualExternMethodEnum(method.getSimpleName().toString())); 5502 } 5503 } 5504 5505 private boolean isExternMethod(JCClassDecl tree, Element e, MethodSymbol method, Type argType) { 5506 long flags = method.flags(); 5507 Type rtype = method.getReturnType(); 5508 5509 // Not necessary to check throws clause in this context 5510 return (flags & PUBLIC) != 0 && (flags & STATIC) == 0 && 5511 types.isSameType(syms.voidType, rtype) && 5512 hasExactlyOneArgWithType(tree, e, method, argType); 5513 } 5514 5515 /** 5516 * Most serialization-related fields and methods on interfaces 5517 * are ineffectual or problematic. 5518 */ 5519 @Override 5520 public Void visitTypeAsInterface(TypeElement e, 5521 JCClassDecl p) { 5522 for(Element el : e.getEnclosedElements()) { 5523 runUnderLint(el, p, (enclosed, tree) -> { 5524 String name = null; 5525 switch(enclosed.getKind()) { 5526 case FIELD -> { 5527 var field = (VarSymbol)enclosed; 5528 name = field.getSimpleName().toString(); 5529 switch(name) { 5530 case "serialPersistentFields" -> { 5531 log.warning(LintCategory.SERIAL, 5532 TreeInfo.diagnosticPositionFor(field, tree), 5533 Warnings.IneffectualSerialFieldInterface); 5534 } 5535 5536 case "serialVersionUID" -> { 5537 checkSerialVersionUID(tree, e, field); 5538 } 5539 } 5540 } 5541 5542 case METHOD -> { 5543 var method = (MethodSymbol)enclosed; 5544 name = enclosed.getSimpleName().toString(); 5545 if (serialMethodNames.contains(name)) { 5546 switch (name) { 5547 case 5548 "readObject", 5549 "readObjectNoData", 5550 "writeObject" -> checkPrivateMethod(tree, e, method); 5551 5552 case 5553 "writeReplace", 5554 "readResolve" -> checkDefaultIneffective(tree, e, method); 5555 5556 default -> throw new AssertionError(); 5557 } 5558 5559 } 5560 }} 5561 }); 5562 } 5563 5564 return null; 5565 } 5566 5567 private void checkPrivateMethod(JCClassDecl tree, 5568 Element e, 5569 MethodSymbol method) { 5570 if ((method.flags() & PRIVATE) == 0) { 5571 log.warning(LintCategory.SERIAL, 5572 TreeInfo.diagnosticPositionFor(method, tree), 5573 Warnings.NonPrivateMethodWeakerAccess); 5574 } 5575 } 5576 5577 private void checkDefaultIneffective(JCClassDecl tree, 5578 Element e, 5579 MethodSymbol method) { 5580 if ((method.flags() & DEFAULT) == DEFAULT) { 5581 log.warning(LintCategory.SERIAL, 5582 TreeInfo.diagnosticPositionFor(method, tree), 5583 Warnings.DefaultIneffective); 5584 5585 } 5586 } 5587 5588 @Override 5589 public Void visitTypeAsAnnotationType(TypeElement e, 5590 JCClassDecl p) { 5591 // Per the JLS, annotation types are not serializeable 5592 return null; 5593 } 5594 5595 /** 5596 * From the Java Object Serialization Specification, 1.13 5597 * Serialization of Records: 5598 * 5599 * "The process by which record objects are serialized or 5600 * externalized cannot be customized; any class-specific 5601 * writeObject, readObject, readObjectNoData, writeExternal, 5602 * and readExternal methods defined by record classes are 5603 * ignored during serialization and deserialization. However, 5604 * a substitute object to be serialized or a designate 5605 * replacement may be specified, by the writeReplace and 5606 * readResolve methods, respectively. Any 5607 * serialPersistentFields field declaration is 5608 * ignored. Documenting serializable fields and data for 5609 * record classes is unnecessary, since there is no variation 5610 * in the serial form, other than whether a substitute or 5611 * replacement object is used. The serialVersionUID of a 5612 * record class is 0L unless explicitly declared. The 5613 * requirement for matching serialVersionUID values is waived 5614 * for record classes." 5615 */ 5616 @Override 5617 public Void visitTypeAsRecord(TypeElement e, 5618 JCClassDecl p) { 5619 boolean isExtern = isExternalizable((Type)e.asType()); 5620 for(Element el : e.getEnclosedElements()) { 5621 runUnderLint(el, p, (enclosed, tree) -> { 5622 String name = enclosed.getSimpleName().toString(); 5623 switch(enclosed.getKind()) { 5624 case FIELD -> { 5625 var field = (VarSymbol)enclosed; 5626 switch(name) { 5627 case "serialPersistentFields" -> { 5628 log.warning(LintCategory.SERIAL, 5629 TreeInfo.diagnosticPositionFor(field, tree), 5630 Warnings.IneffectualSerialFieldRecord); 5631 } 5632 5633 case "serialVersionUID" -> { 5634 // Could generate additional warning that 5635 // svuid value is not checked to match for 5636 // records. 5637 checkSerialVersionUID(tree, e, field); 5638 }} 5639 } 5640 5641 case METHOD -> { 5642 var method = (MethodSymbol)enclosed; 5643 switch(name) { 5644 case "writeReplace" -> hasAppropriateWriteReplace(tree, method, true); 5645 case "readResolve" -> checkReadResolve(tree, e, method); 5646 5647 case "writeExternal" -> checkWriteExternalRecord(tree, e, method, isExtern); 5648 case "readExternal" -> checkReadExternalRecord(tree, e, method, isExtern); 5649 5650 default -> { 5651 if (serialMethodNames.contains(name)) { 5652 log.warning(LintCategory.SERIAL, 5653 TreeInfo.diagnosticPositionFor(method, tree), 5654 Warnings.IneffectualSerialMethodRecord(name)); 5655 } 5656 }} 5657 }}}); 5658 } 5659 return null; 5660 } 5661 5662 boolean isConcreteInstanceMethod(JCClassDecl tree, 5663 MethodSymbol method, 5664 boolean warn) { 5665 if ((method.flags() & (STATIC | ABSTRACT)) != 0) { 5666 if (warn) { 5667 log.warning(LintCategory.SERIAL, 5668 TreeInfo.diagnosticPositionFor(method, tree), 5669 Warnings.SerialConcreteInstanceMethod(method.getSimpleName())); 5670 } 5671 return false; 5672 } 5673 return true; 5674 } 5675 5676 private boolean isExpectedReturnType(JCClassDecl tree, 5677 MethodSymbol method, 5678 Type expectedReturnType, 5679 boolean warn) { 5680 // Note: there may be complications checking writeReplace 5681 // and readResolve since they return Object and could, in 5682 // principle, have covariant overrides and any synthetic 5683 // bridge method would not be represented here for 5684 // checking. 5685 Type rtype = method.getReturnType(); 5686 if (!types.isSameType(expectedReturnType, rtype)) { 5687 if (warn) { 5688 log.warning(LintCategory.SERIAL, 5689 TreeInfo.diagnosticPositionFor(method, tree), 5690 Warnings.SerialMethodUnexpectedReturnType(method.getSimpleName(), 5691 rtype, expectedReturnType)); 5692 } 5693 return false; 5694 } 5695 return true; 5696 } 5697 5698 private void checkOneArg(JCClassDecl tree, 5699 Element enclosing, 5700 MethodSymbol method, 5701 Type expectedType) { 5702 String name = method.getSimpleName().toString(); 5703 5704 var parameters= method.getParameters(); 5705 5706 if (parameters.size() != 1) { 5707 log.warning(LintCategory.SERIAL, 5708 TreeInfo.diagnosticPositionFor(method, tree), 5709 Warnings.SerialMethodOneArg(method.getSimpleName(), parameters.size())); 5710 return; 5711 } 5712 5713 Type parameterType = parameters.get(0).asType(); 5714 if (!types.isSameType(parameterType, expectedType)) { 5715 log.warning(LintCategory.SERIAL, 5716 TreeInfo.diagnosticPositionFor(method, tree), 5717 Warnings.SerialMethodParameterType(method.getSimpleName(), 5718 expectedType, 5719 parameterType)); 5720 } 5721 } 5722 5723 private boolean hasExactlyOneArgWithType(JCClassDecl tree, 5724 Element enclosing, 5725 MethodSymbol method, 5726 Type expectedType) { 5727 var parameters = method.getParameters(); 5728 return (parameters.size() == 1) && 5729 types.isSameType(parameters.get(0).asType(), expectedType); 5730 } 5731 5732 5733 boolean hasNoArgs(JCClassDecl tree, MethodSymbol method, boolean warn) { 5734 var parameters = method.getParameters(); 5735 if (!parameters.isEmpty()) { 5736 if (warn) { 5737 log.warning(LintCategory.SERIAL, 5738 TreeInfo.diagnosticPositionFor(parameters.get(0), tree), 5739 Warnings.SerialMethodNoArgs(method.getSimpleName())); 5740 } 5741 return false; 5742 } 5743 return true; 5744 } 5745 5746 private void checkExternalizable(JCClassDecl tree, Element enclosing, MethodSymbol method) { 5747 // If the enclosing class is externalizable, warn for the method 5748 if (isExternalizable((Type)enclosing.asType())) { 5749 log.warning(LintCategory.SERIAL, 5750 TreeInfo.diagnosticPositionFor(method, tree), 5751 Warnings.IneffectualSerialMethodExternalizable(method.getSimpleName())); 5752 } 5753 return; 5754 } 5755 5756 private boolean hasExpectedExceptions(JCClassDecl tree, 5757 MethodSymbol method, 5758 boolean warn, 5759 Type... declaredExceptions) { 5760 for (Type thrownType: method.getThrownTypes()) { 5761 // For each exception in the throws clause of the 5762 // method, if not an Error and not a RuntimeException, 5763 // check if the exception is a subtype of a declared 5764 // exception from the throws clause of the 5765 // serialization method in question. 5766 if (types.isSubtype(thrownType, syms.runtimeExceptionType) || 5767 types.isSubtype(thrownType, syms.errorType) ) { 5768 continue; 5769 } else { 5770 boolean declared = false; 5771 for (Type declaredException : declaredExceptions) { 5772 if (types.isSubtype(thrownType, declaredException)) { 5773 declared = true; 5774 continue; 5775 } 5776 } 5777 if (!declared) { 5778 if (warn) { 5779 log.warning(LintCategory.SERIAL, 5780 TreeInfo.diagnosticPositionFor(method, tree), 5781 Warnings.SerialMethodUnexpectedException(method.getSimpleName(), 5782 thrownType)); 5783 } 5784 return false; 5785 } 5786 } 5787 } 5788 return true; 5789 } 5790 5791 private <E extends Element> Void runUnderLint(E symbol, JCClassDecl p, BiConsumer<E, JCClassDecl> task) { 5792 Lint prevLint = lint; 5793 try { 5794 lint = lint.augment((Symbol) symbol); 5795 5796 if (lint.isEnabled(LintCategory.SERIAL)) { 5797 task.accept(symbol, p); 5798 } 5799 5800 return null; 5801 } finally { 5802 lint = prevLint; 5803 } 5804 } 5805 5806 } 5807 5808 }