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

Incorrect handling of mandated parameter names in MethodParameters attributes

    XMLWordPrintable

Details

    • Bug
    • Resolution: Fixed
    • P4
    • 11
    • 9
    • tools
    • None
    • b01

    Description

      When reading MethodParameters attributes, javac reads the names of all provided parameters including 'mandated' parameters (e.g. the enclosing instance parameter of inner classes) [1]. When setting the parameters names of a MethodSymbol it only skips over enclosing instance parameters if the names were inferred from the local variable table, and not if they were read from the MethodParameters attribute [2].

      The result is that mandated parameters names read from the MethodParameter attribute are used for non-mandated parameters, and the real names are offset.

      [1] http://hg.openjdk.java.net/jdk9/dev/langtools/file/ee787e34231d/src/jdk.compiler/share/classes/com/sun/tools/javac/jvm/ClassReader.java#l1288
      [2] http://hg.openjdk.java.net/jdk9/dev/langtools/file/ee787e34231d/src/jdk.compiler/share/classes/com/sun/tools/javac/jvm/ClassReader.java#l2476

      Skipping over mandated parameter names in MethodParameter attributes avoids this issue:

      diff -r 9b2de82e7e49 src/jdk.compiler/share/classes/com/sun/tools/javac/jvm/ClassReader.java
      --- a/src/jdk.compiler/share/classes/com/sun/tools/javac/jvm/ClassReader.java Wed Feb 15 16:18:18 2017 -0800
      +++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/jvm/ClassReader.java Thu Mar 23 15:22:23 2017 -0700
      @@ -1285,10 +1285,14 @@
                               int numEntries = nextByte();
                               parameterNameIndices = new int[numEntries];
                               haveParameterNameIndices = true;
      + int index = 0;
                               for (int i = 0; i < numEntries; i++) {
                                   int nameIndex = nextChar();
                                   int flags = nextChar();
      - parameterNameIndices[i] = nameIndex;
      + if ((flags & Flags.MANDATED) == Flags.MANDATED) {
      + continue;
      + }
      + parameterNameIndices[index++] = nameIndex;
                               }
                           }
                           bp = newbp;

      Repro:

      === ./plugin/module-info.java
      module parameterplugin {
        requires transitive jdk.compiler;
        provides com.sun.source.util.Plugin with parameterplugin.ParameterPlugin;
      }
      === ./plugin/parameterplugin/ParameterPlugin.java
      package parameterplugin;

      import static java.util.stream.Collectors.joining;

      import com.sun.source.tree.*;
      import com.sun.source.util.*;
      import javax.lang.model.element.*;

      public class ParameterPlugin implements Plugin {

        @Override
        public String getName() {
          return "ParameterPlugin";
        }

        @Override
        public void init(JavacTask javacTask, String... strings) {
          javacTask.addTaskListener(
              new TaskListener() {
                @Override
                public void finished(TaskEvent e) {
                  if (e.getKind() != TaskEvent.Kind.ENTER) {
                    return;
                  }
                  new TreePathScanner<Void, Void>() {
                    @Override
                    public Void visitNewClass(NewClassTree node, Void aVoid) {
                      ExecutableElement e =
                          (ExecutableElement) Trees.instance(javacTask).getElement(getCurrentPath());
                      System.err.println(
                          e.getParameters()
                              .stream()
                              .map(p -> p.asType() + " " + p.getSimpleName())
                              .collect(joining(", ")));
                      return null;
                    }
                  }.scan(new TreePath(e.getCompilationUnit()), null);
                }
              });
        }
      }
      === ./A.java
      class A {
        class I {
          I(int a, int b) {}
        }
      }
      === ./B.java
      class B {
        void f(A a) {
          a.new I(1, 2);
        }
      }
      ===

      Actual:

      $ javac -parameters $(find . -name "*.java")
      $ javac --processor-module-path plugin -Xplugin:Parameter
      Plugin B.java -sourcepath : -parameters
      int this$0, int a

      Expected:

      int a, int b

      Attachments

        Activity

          People

            cushon Liam Miller-Cushon
            cushon Liam Miller-Cushon
            Votes:
            0 Vote for this issue
            Watchers:
            2 Start watching this issue

            Dates

              Created:
              Updated:
              Resolved: