changeset 2946:1f4198a7d9da

fix problems with locating module-info on the sourcepath/classpath
author jjg
date Thu, 26 Mar 2015 15:21:23 -0700
parents 6524d1ef199a
children 2e29011b30ee
files src/jdk.compiler/share/classes/com/sun/tools/javac/code/ClassFinder.java src/jdk.compiler/share/classes/com/sun/tools/javac/code/ModuleFinder.java src/jdk.compiler/share/classes/com/sun/tools/javac/code/Symbol.java src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Modules.java src/jdk.compiler/share/classes/com/sun/tools/javac/jvm/ClassReader.java src/jdk.compiler/share/classes/com/sun/tools/javac/util/Name.java test/tools/javac/modules/ModuleTestBase.java test/tools/javac/modules/MultiModuleModeTest.java test/tools/javac/modules/SingleModuleModeTest.java
diffstat 9 files changed, 159 insertions(+), 25 deletions(-) [+]
line wrap: on
line diff
--- a/src/jdk.compiler/share/classes/com/sun/tools/javac/code/ClassFinder.java	Sun Mar 15 12:42:33 2015 -0700
+++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/code/ClassFinder.java	Thu Mar 26 15:21:23 2015 -0700
@@ -341,7 +341,7 @@
                 }
                 currentClassFile = classfile;
                 if (verbose) {
-                    log.printVerbose("loading", currentClassFile.toString());
+                    log.printVerbose("loading", currentClassFile.getName());
                 }
                 if (classfile.getKind() == JavaFileObject.Kind.CLASS) {
                     reader.readClassFile(c);
--- a/src/jdk.compiler/share/classes/com/sun/tools/javac/code/ModuleFinder.java	Sun Mar 15 12:42:33 2015 -0700
+++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/code/ModuleFinder.java	Thu Mar 26 15:21:23 2015 -0700
@@ -38,6 +38,7 @@
 import javax.tools.JavaFileObject.Kind;
 import javax.tools.StandardLocation;
 
+import com.sun.tools.javac.code.Scope.WriteableScope;
 import com.sun.tools.javac.code.Symbol.ClassSymbol;
 import com.sun.tools.javac.code.Symbol.CompletionFailure;
 import com.sun.tools.javac.code.Symbol.ModuleSymbol;
@@ -202,15 +203,26 @@
                 // Note: the following may trigger a re-entrant call to Modules.enter
                 msym = new ModuleSymbol();
                 ClassSymbol info = new ClassSymbol(Flags.MODULE, names.module_info, msym);
+                info.modle = msym;
+                info.classfile = fo;
+                info.members_field = WriteableScope.create(info);
                 msym.module_info = info;
-                msym.module_info.classfile = fo;
                 // TODO: defer with completer?
-                classFinder.fillIn(msym.module_info);
+                classFinder.fillIn(info);
+                // TODO: should we do the following here, or as soon as we find the name in
+                // the source or class file?
+                // Consider the case when the class/source path module shadows one on the
+                // module source path
+                if (syms.modules.get(msym.name) != null) {
+                    // error: module already defined
+                    System.err.println("ERROR: module already defined: " + msym);
+                } else {
+                    syms.modules.put(msym.name, msym);
+                }
             }
 
             msym.sourceLocation = StandardLocation.SOURCE_PATH;
             msym.classLocation = StandardLocation.CLASS_PATH;
-
             return msym;
 
         } catch (IOException e) {
--- a/src/jdk.compiler/share/classes/com/sun/tools/javac/code/Symbol.java	Sun Mar 15 12:42:33 2015 -0700
+++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/code/Symbol.java	Thu Mar 26 15:21:23 2015 -0700
@@ -835,7 +835,7 @@
     public static class ModuleSymbol extends TypeSymbol // JIGSAW need TypeSymbol?
             /*implements ModuleElement*/ {
 
-        public Name fullname;
+        public Name fullname; // TODO: do we need this?
         public Name version;
         public JavaFileManager.Location sourceLocation;
         public JavaFileManager.Location classLocation;
@@ -888,7 +888,8 @@
 
         @Override
         public String toString() {
-            // the following strings should be localized
+            // TODO: the following strings should be localized
+            // Do this with custom anon subtypes in Symtab
             String n = (fullname == null) ? "<unknown>"
                     : (fullname.isEmpty()) ? "<unnamed>"
                     : String.valueOf(fullname);
--- a/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Modules.java	Sun Mar 15 12:42:33 2015 -0700
+++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Modules.java	Thu Mar 26 15:21:23 2015 -0700
@@ -193,14 +193,24 @@
         if (isModuleInfo && isModuleDecl) {
             JCModuleDecl decl = (JCModuleDecl) toplevel.defs.head;
             Name name = TreeInfo.fullName(decl.qualId);
-            // TODO, This is the point to determine if the tree should satisfy ClassSymbol c
-            ModuleSymbol sym = syms.enterModule(name);
-            if (sym.module_info.sourcefile != null) {
-                log.error(decl.pos(), "duplicate.module", name);
-                return;
+            ModuleSymbol sym;
+            if (c != null) {
+               sym = (ModuleSymbol) c.owner;
+               if (sym.name == null) {
+                   sym.fullname = sym.name = name;
+                   c.fullname = c.flatname = name.append('.', names.module_info);
+               } else {
+                   // TODO: validate name
+               }
+            } else {
+                sym = syms.enterModule(name);
+                if (sym.module_info.sourcefile != null) {
+                    log.error(decl.pos(), "duplicate.module", name);
+                    return;
+                }
             }
+            sym.completer = getSourceCompleter(toplevel);
             sym.module_info.sourcefile = toplevel.sourcefile;
-            sym.completer = getSourceCompleter(toplevel);
             decl.sym = sym;
 
             if (multiModuleMode || modules.isEmpty()) {
@@ -258,7 +268,17 @@
                     case 0:
                         defaultModule = moduleFinder.findSingleModule();
                         if (defaultModule == syms.unnamedModule) {
+                            // Question: why not do findAllModules and initVisiblePackages here?
+                            // i.e. body of unnamedModuleCompleter
                             defaultModule.completer = getUnnamedModuleCompleter();
+                        } else {
+                            // Question: why not do completeModule here?
+                            defaultModule.completer = new Completer() {
+                                @Override
+                                public void complete(Symbol sym) throws CompletionFailure {
+                                    completeModule((ModuleSymbol) sym);
+                                }
+                            };
                         }
                         rootModules.add(defaultModule);
                         break;
--- a/src/jdk.compiler/share/classes/com/sun/tools/javac/jvm/ClassReader.java	Sun Mar 15 12:42:33 2015 -0700
+++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/jvm/ClassReader.java	Thu Mar 26 15:21:23 2015 -0700
@@ -2265,16 +2265,29 @@
             // read own class name and check that it matches
             ClassSymbol self = readClassSymbol(nextChar());
             if (c != self) {
-                System.err.println("CR: " + c);
-                System.err.println("CR: flags (orig) " + Flags.toString(f));
-                System.err.println("CR: flags  (adj) " + Flags.toString(flags));
                 throw badClassFile("class.file.wrong.class",
                                    self.flatname);
             }
         } else {
             c.flags_field = flags;
             // TODO: validate name
-            nextChar();
+            int i = nextChar();
+            // TODO: refactor some of this to a new method readModuleName
+            int classIndex = poolIdx[i];
+            if (buf[classIndex] == CONSTANT_Class) {
+                int utf8Index = poolIdx[getChar(classIndex + 1)];
+                if (buf[utf8Index] == CONSTANT_Utf8) {
+                    int len = getChar(utf8Index + 1);
+                    int start = utf8Index + 3;
+                    Name modInfoName = names.fromUtf(internalize(buf, start, len));
+                    if (c.owner.name == null) {
+                        Name moduleName = Convert.packagePart(modInfoName);
+                        ((ModuleSymbol) c.owner).fullname = c.owner.name = moduleName;
+                        c.fullname = c.flatname = modInfoName;
+                    }
+                }
+            }
+
         }
 
         // class attributes must be read before class
--- a/src/jdk.compiler/share/classes/com/sun/tools/javac/util/Name.java	Sun Mar 15 12:42:33 2015 -0700
+++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/util/Name.java	Thu Mar 26 15:21:23 2015 -0700
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 1999, 2012, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1999, 2015, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -127,9 +127,11 @@
         int prefixOffset   = prefix.getByteOffset();
         int prefixLength   = prefix.getByteLength();
 
+        if (thisLength < prefixLength)
+            return false;
+
         int i = 0;
         while (i < prefixLength &&
-               i < thisLength &&
                thisBytes[thisOffset + i] == prefixBytes[prefixOffset + i])
             i++;
         return i == prefixLength;
--- a/test/tools/javac/modules/ModuleTestBase.java	Sun Mar 15 12:42:33 2015 -0700
+++ b/test/tools/javac/modules/ModuleTestBase.java	Thu Mar 26 15:21:23 2015 -0700
@@ -68,7 +68,8 @@
                     m.invoke(this, new Object[] { baseDir });
                 } catch (InvocationTargetException e) {
                     Throwable cause = e.getCause();
-                    throw (cause instanceof Exception) ? ((Exception) cause) : e;
+                    error("Exception: " + e.getCause());
+                    cause.printStackTrace(out);
                 }
                 out.println();
             }
@@ -94,4 +95,9 @@
         });
         return list.toArray(new Path[list.size()]);
     }
+
+    void error(String message) {
+        out.println("Error: " + message);
+        errors++;
+    }
 }
--- a/test/tools/javac/modules/MultiModuleModeTest.java	Sun Mar 15 12:42:33 2015 -0700
+++ b/test/tools/javac/modules/MultiModuleModeTest.java	Thu Mar 26 15:21:23 2015 -0700
@@ -31,6 +31,7 @@
  * @run main MultiModuleModeTest
  */
 
+import java.nio.file.Files;
 import java.nio.file.Path;
 import java.util.ArrayList;
 import java.util.Arrays;
@@ -88,6 +89,50 @@
             throw new Exception("expected output not found");
     }
 
+    @Test
+    void testImplicitModuleSource(Path base) throws Exception {
+        Path src = base.resolve("src");
+        tb.writeJavaFiles(src.resolve("m1"), "module m1 { }");
+        tb.writeJavaFiles(src.resolve("m2"), "module m2 { requires m1; }");
+        Path modules = base.resolve("modules");
+        Files.createDirectories(modules);
+
+        tb.new JavacTask()
+                .options("-modulesourcepath", src.toString())
+                .outdir(modules.toString()) // should allow Path here
+                .files(src.resolve("m2/module-info.java"))
+                .run()
+                .writeAll();
+    }
+
+    @Test
+    void testImplicitModuleClass(Path base) throws Exception {
+        Path src1 = base.resolve("src1");
+        tb.writeJavaFiles(src1.resolve("m1"), "module m1 { }");
+        Path modules1 = base.resolve("modules1");
+        Files.createDirectories(modules1);
+
+        tb.new JavacTask()
+                .options("-modulesourcepath", src1.toString())
+                .outdir(modules1.toString()) // should allow Path here
+                .files(src1.resolve("m1/module-info.java"))
+                .run()
+                .writeAll();
+
+        Path src2= base.resolve("src2");
+        tb.writeJavaFiles(src2.resolve("m2"), "module m2 { requires m1; }");
+        Path modules2 = base.resolve("modules2");
+        Files.createDirectories(modules2);
+
+        tb.new JavacTask()
+                .options("-modulepath", modules1.toString(),
+                        "-modulesourcepath", src2.toString())
+                .outdir(modules2.toString()) // should allow Path here
+                .files(src2.resolve("m2/module-info.java"))
+                .run()
+                .writeAll();
+    }
+
     Path[] join(Path[] a, Path[] b) {
         List<Path> result = new ArrayList<>();
         result.addAll(Arrays.asList(a));
--- a/test/tools/javac/modules/SingleModuleModeTest.java	Sun Mar 15 12:42:33 2015 -0700
+++ b/test/tools/javac/modules/SingleModuleModeTest.java	Thu Mar 26 15:21:23 2015 -0700
@@ -31,8 +31,8 @@
  * @run main SingleModuleModeTest
  */
 
+import java.nio.file.Files;
 import java.nio.file.Path;
-import java.nio.file.Paths;
 
 public class SingleModuleModeTest extends ModuleTestBase{
 
@@ -40,19 +40,18 @@
         new SingleModuleModeTest().run();
     }
 
-    Path src;
-
     void run() throws Exception {
         tb = new ToolBox();
-        src = Paths.get("src");
-        tb.writeJavaFiles(src.resolve("m1"), "module m1 { }");
-        tb.writeJavaFiles(src.resolve("m2"), "module m2 { }");
 
         runTests();
     }
 
     @Test
     void testTooManyModules(Path base) throws Exception {
+        Path src = base.resolve("src");
+        tb.writeJavaFiles(src.resolve("m1"), "module m1 { }");
+        tb.writeJavaFiles(src.resolve("m2"), "module m2 { }");
+
         String log = tb.new JavacTask()
                 .options("-XDrawDiagnostics")
                 .files(findJavaFiles(src))
@@ -63,4 +62,40 @@
         if (!log.contains("module-info.java:1:1: compiler.err.too.many.modules"))
             throw new Exception("expected output not found");
     }
+
+    @Test
+    void testImplicitModuleSource(Path base) throws Exception {
+        Path src = base.resolve("src");
+        tb.writeJavaFiles(src,
+                "module m { }",
+                "class C { }");
+
+        tb.new JavacTask()
+                .classpath(src.toString()) // should allow Path here
+                .files(src.resolve("C.java"))
+                .run()
+                .writeAll();
+    }
+
+    @Test
+    void testImplicitModuleClass(Path base) throws Exception {
+        Path src = base.resolve("src");
+        tb.writeJavaFiles(src,
+                "module m { }",
+                "class C { }");
+        Path classes = base.resolve("classes");
+        Files.createDirectories(classes);
+
+        tb.new JavacTask()
+                .outdir(classes.toString()) // should allow Path here
+                .files(src.resolve("module-info.java"))
+                .run()
+                .writeAll();
+
+        tb.new JavacTask()
+                .classpath(classes.toString()) // should allow Path here
+                .files(src.resolve("C.java"))
+                .run()
+                .writeAll();
+    }
 }