Uploaded image for project: 'JDK'
  1. JDK
  2. JDK-8316470

Incorrect error location for "invalid permits clause" depending on file order

XMLWordPrintable

    • b21
    • generic
    • generic

      ADDITIONAL SYSTEM INFORMATION :
      JDK: Temurin 20.0.2+9

      Edition Windows 10 Pro
      Version 22H2
      OS build 19045.3448
      Experience Windows Feature Experience Pack 1000.19044.1000.0


      A DESCRIPTION OF THE PROBLEM :
      Depending on the order that you give the files to the compiler, the error for an "invalid permits clause" (where a child of a sealed class does not actually extend that class) is either given in the correct location, or an incorrect arbitrary location (I have seen it given in the middle of a comment in a totally separate class). I do not believe that the file ordering should matter, and even if it did, this is surely still an incorrect behaviour.

      The source code given below reproduces the behaviour every time on the latest JDK.

      STEPS TO FOLLOW TO REPRODUCE THE PROBLEM :
      Compile and run the source code below, using Java 20.0.2+9 (also seen on Java 17). No external libraries are needed.

      EXPECTED VERSUS ACTUAL BEHAVIOR :
      EXPECTED -
      I expected that in both compilations performed in the source code, the error should be indicated at the same place (the "BadChild" token on line 2 of Parent.java).
      ACTUAL -
      In the second case (the "bug order"), it indicates the error on line 4 of GoodChild.java.

      ---------- BEGIN SOURCE ----------
      package org.example;

      import javax.tools.Diagnostic;
      import javax.tools.DiagnosticListener;
      import javax.tools.JavaCompiler;
      import javax.tools.JavaFileObject;
      import javax.tools.StandardJavaFileManager;
      import javax.tools.StandardLocation;
      import javax.tools.ToolProvider;
      import java.io.File;
      import java.io.IOException;
      import java.nio.charset.StandardCharsets;
      import java.nio.file.Files;
      import java.util.List;
      import java.util.stream.Collectors;

      public class Main
      {
          public static void main(String[] args) throws IOException
          {
              File dir = Files.createTempDirectory("sealed-error-bug").toFile();
              File parent = new File(dir, "Parent.java");
              Files.write(parent.toPath(), """
                  // Parent is sealed and indicates two sub classes
                  sealed class Parent permits GoodChild, BadChild
                  {
                  }
              """.lines().collect(Collectors.toList()));

              File goodChild = new File(dir, "GoodChild.java");
              Files.write(goodChild.toPath(), """
                  // GoodChild extends the sealed parent
                  final class GoodChild extends Parent
                  {
                  }
              """.lines().collect(Collectors.toList()));

              File badChild = new File(dir, "BadChild.java");
              Files.write(badChild.toPath(), """
                  // BadChild does not extend the sealed parent
                  final class BadChild
                  {
                  }
              """.lines().collect(Collectors.toList()));

              DiagnosticListener<JavaFileObject> diagListener = new DiagnosticListener<JavaFileObject>()
              {
                  @Override
                  public void report(Diagnostic<? extends JavaFileObject> diagnostic)
                  {
                      System.out.println(diagnostic);
                  }
              };

              JavaCompiler jc = ToolProvider.getSystemJavaCompiler();
              StandardJavaFileManager sjfm = jc.getStandardFileManager(diagListener, null, StandardCharsets.UTF_8);
              sjfm.setLocation(StandardLocation.SOURCE_PATH, List.of(dir));
              sjfm.setLocation(StandardLocation.CLASS_PATH, List.of(dir));
              sjfm.setLocation(StandardLocation.CLASS_OUTPUT, List.of(dir));
              Iterable<? extends JavaFileObject> goodOrderOfInputs =
                  sjfm.getJavaFileObjectsFromFiles(List.of(parent, goodChild, badChild));
              System.out.println("Compiling with fine order...");
              jc.getTask(null, sjfm, diagListener, List.of("-g", "-deprecation"), null, goodOrderOfInputs).call();
              Iterable<? extends JavaFileObject> badOrderOfInputs =
                  sjfm.getJavaFileObjectsFromFiles(List.of(goodChild, badChild, parent));
              System.out.println("Compiling with bug order...");
              jc.getTask(null, sjfm, diagListener, List.of("-g", "-deprecation"), null, badOrderOfInputs).call();
          }
      }

      ---------- END SOURCE ----------

      CUSTOMER SUBMITTED WORKAROUND :
      Pass the files in the right order, although it is not clear how to determine what the right order should be in all cases.

      FREQUENCY : always


            jlahoda Jan Lahoda
            webbuggrp Webbug Group
            Votes:
            0 Vote for this issue
            Watchers:
            4 Start watching this issue

              Created:
              Updated:
              Resolved: