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

Compiler API returns a Diagnostic object which breaks invariant specified by doc

    Details

    • Type: Bug
    • Status: Open
    • Priority: P4
    • Resolution: Unresolved
    • Affects Version/s: 7
    • Fix Version/s: tbd_minor
    • Component/s: tools
    • Labels:
    • Subcomponent:
    • CPU:
      x86
    • OS:
      linux

      Description

      FULL PRODUCT VERSION :
      java version "1.7.0_03"
      Java(TM) SE Runtime Environment (build 1.7.0_03-b04)
      Java HotSpot(TM) Server VM (build 22.1-b02, mixed mode)


      ADDITIONAL OS VERSION INFORMATION :
      Ubuntu 11.04 linux

      A DESCRIPTION OF THE PROBLEM :
      We are using the tools/compiler API (javax.tools.*). The Diagnostic interface (javax.tools.Diagnostic) documentation for the 'getEndPosition()' method specifies that the method -

          Returns:
             offset from beginning of file; NOPOS if and only if getPosition() returns NOPOS

      - yet we have found an error for which this is not true. Occurs when an implicit superclass constructor call doesn't match the signature of the superclass constructor. See test case below.


      STEPS TO FOLLOW TO REPRODUCE THE PROBLEM :
      1. Write code which uses the javax.tools.* API
      2. Use it to compile code with an implicit constructor call to a non-existing superclass constructor (see test case for example)
      3. Check the 'Diagnostic' object that is returned

      EXPECTED VERSUS ACTUAL BEHAVIOR :
      EXPECTED -
      (getStartPosition() == NOPOS || getEndPosition() != NOPOS), as per documentation

      ACTUAL -
      (getStartPosition() != NOPOS && getEndPosition() == NOPOS) instead.


      REPRODUCIBILITY :
      This bug can be reproduced always.

      ---------- BEGIN SOURCE ----------
      import java.io.IOException;
      import java.io.InputStream;
      import java.io.OutputStream;
      import java.io.Reader;
      import java.io.Writer;
      import java.net.URI;
      import java.util.Iterator;
      import java.util.LinkedList;
      import java.util.List;
      import java.util.Set;

      import javax.lang.model.element.Modifier;
      import javax.lang.model.element.NestingKind;
      import javax.tools.Diagnostic;
      import javax.tools.DiagnosticListener;
      import javax.tools.FileObject;
      import javax.tools.ForwardingJavaFileManager;
      import javax.tools.JavaCompiler;
      import javax.tools.JavaFileManager;
      import javax.tools.JavaFileObject;
      import javax.tools.JavaFileObject.Kind;
      import javax.tools.SimpleJavaFileObject;
      import javax.tools.StandardJavaFileManager;
      import javax.tools.ToolProvider;

      import sun.reflect.generics.reflectiveObjects.NotImplementedException;

      import com.sun.xml.internal.messaging.saaj.util.ByteInputStream;


      public class TestCAPI
      {
          public static void main(String [] args) throws Exception
          {
              final Diagnostic<? extends JavaFileObject>[] diags = new Diagnostic[1];
              
              JavaCompiler jc = ToolProvider.getSystemJavaCompiler();
              DiagnosticListener<JavaFileObject> diagListener = new DiagnosticListener<JavaFileObject>() {
                  @Override
                  public void report(Diagnostic<? extends JavaFileObject> diag)
                  {
                      //System.out.println("Got diag: " + diag);
                      //System.out.println(" Start pos: " + diag.getStartPosition());
                      //System.out.println(" End pos: " + diag.getEndPosition());
                      diags[0] = diag;
                  }
              };
              
              List<String> optionsList = new LinkedList<String>();
              
              final String egSrc = "class One { public One(int nn) { } }\n" +
                      "class Two extends One { public Two() { } }\n";
              final byte[] srcBuf = egSrc.getBytes();
              
              List<JavaFileObject> sources = new LinkedList<JavaFileObject>();
              URI egFileUri = new URI("test://Two.java");
              SimpleJavaFileObject srcObject= new SimpleJavaFileObject(egFileUri, Kind.SOURCE) {
                  @Override
                  public InputStream openInputStream() throws IOException
                  {
                      return new ByteInputStream(srcBuf, srcBuf.length);
                  }
                  
                  @Override
                  public CharSequence getCharContent(boolean ignoreEncodingErrors)
                          throws IOException
                  {
                      return egSrc;
                  }
                  
                  @Override
                  public Reader openReader(boolean ignoreEncodingErrors)
                          throws IOException
                  {
                      throw new NotImplementedException();
                  }
              };
              sources.add(srcObject);
              
              StandardJavaFileManager sjfm = jc.getStandardFileManager(diagListener, null, null);
              
              JavaFileManager jfm = new ForwardingJavaFileManager<StandardJavaFileManager>(sjfm) {
                  @Override
                  public void close() throws IOException
                  {
                      throw new NotImplementedException();
                  }
                  
                  @Override
                  public void flush() throws IOException
                  {
                  }
                  
                  @Override
                  public FileObject getFileForInput(Location location,
                          String packageName, String relativeName) throws IOException
                  {
                      throw new NotImplementedException();
                  }
                  
                  @Override
                  public FileObject getFileForOutput(Location location,
                          String packageName, String relativeName, FileObject sibling)
                          throws IOException
                  {
                      throw new NotImplementedException();
                  }
                  
                  @Override
                  public JavaFileObject getJavaFileForInput(Location location,
                          String className, Kind kind) throws IOException
                  {
                      throw new NotImplementedException();
                  }
                  
                  @Override
                  public JavaFileObject getJavaFileForOutput(Location location,
                          String className, Kind kind, FileObject sibling)
                          throws IOException
                  {
                      return new JavaFileObject() {
                          @Override
                          public boolean delete()
                          {
                              return true;
                          }
                          @Override
                          public Modifier getAccessLevel()
                          {
                              return null;
                          }
                          @Override
                          public CharSequence getCharContent(boolean ignoreEncodingErrors) throws IOException
                          {
                              throw new NotImplementedException();
                          }
                          @Override
                          public Kind getKind()
                          {
                              throw new NotImplementedException();
                          }
                          @Override
                          public long getLastModified()
                          {
                              throw new NotImplementedException();
                          }
                          @Override
                          public String getName()
                          {
                              throw new NotImplementedException();
                          }
                          @Override
                          public NestingKind getNestingKind()
                          {
                              return null;
                          }
                          @Override
                          public boolean isNameCompatible(String simpleName, Kind kind)
                          {
                              throw new NotImplementedException();
                          }
                          @Override
                          public InputStream openInputStream() throws IOException
                          {
                              throw new NotImplementedException();
                          }
                          @Override
                          public OutputStream openOutputStream() throws IOException
                          {
                              return new OutputStream() {
                                  @Override
                                  public void write(int b) throws IOException
                                  {
                                  }
                                  @Override
                                  public void write(byte[] b) throws IOException
                                  {
                                  }
                                  @Override
                                  public void write(byte[] b, int off, int len)
                                          throws IOException
                                  {
                                  }
                              };
                          }
                          @Override
                          public Reader openReader(boolean ignoreEncodingErrors)
                                  throws IOException
                          {
                              throw new NotImplementedException();
                          }
                          @Override
                          public Writer openWriter() throws IOException
                          {
                              throw new NotImplementedException();
                          }
                          @Override
                          public URI toUri()
                          {
                              throw new NotImplementedException();
                          }
                      };
                  }
                  
                  @Override
                  public boolean handleOption(String current,
                          Iterator<String> remaining)
                  {
                      throw new NotImplementedException();
                  }
                  
                  @Override
                  public String inferBinaryName(Location location, JavaFileObject file)
                  {
                      return super.inferBinaryName(location, file);
                  }
                  
                  @Override
                  public boolean isSameFile(FileObject a, FileObject b)
                  {
                      throw new NotImplementedException();
                  }
                  
                  @Override
                  public int isSupportedOption(String arg0)
                  {
                      throw new NotImplementedException();
                  }
                  
                  @Override
                  public Iterable<JavaFileObject> list(Location location,
                          String packageName, Set<Kind> kinds, boolean recurse)
                          throws IOException
                  {
                      return super.list(location, packageName, kinds, recurse);
                  }
              };
              
              
              jc.getTask(null, jfm, diagListener, optionsList, null, sources).call();
              
              if (diags[0].getStartPosition() != Diagnostic.NOPOS
                      && diags[0].getEndPosition() == Diagnostic.NOPOS)
              {
                  System.err.println("Error - start position is set but end position is NOPOS");
                  System.exit(1);
              }
              System.exit(0);
          }
      }

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

      CUSTOMER SUBMITTED WORKAROUND :
      Check for condition getEndPosition() == NOPOS and use getStartPosition() as an approximation in that case.

        Attachments

          Issue Links

            Activity

              People

              • Assignee:
                Unassigned
                Reporter:
                webbuggrp Webbug Group
              • Votes:
                0 Vote for this issue
                Watchers:
                4 Start watching this issue

                Dates

                • Created:
                  Updated:
                  Imported:
                  Indexed: