# HG changeset patch # User jjg # Date 1492730020 25200 # Node ID b8a35541a0486205ff5585daf06505421828e995 # Parent 9be30ec2401e7db745c622d928ebf101407f9a0c 8178017: JDK 9 change to symlink handling causes misleading class.public.should.be.in.file diagnostic Reviewed-by: jlahoda, cushon diff -r 9be30ec2401e -r b8a35541a048 src/jdk.compiler/share/classes/com/sun/tools/javac/file/PathFileObject.java --- a/src/jdk.compiler/share/classes/com/sun/tools/javac/file/PathFileObject.java Thu Apr 20 14:37:15 2017 -0700 +++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/file/PathFileObject.java Thu Apr 20 16:13:40 2017 -0700 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2009, 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2009, 2017, 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 @@ -150,6 +150,7 @@ * @param fileManager the file manager creating this file object * @param path the path referred to by this file object * @param userJarPath the path of the jar file containing the file system. + * @return the file object */ public static PathFileObject forJarPath(BaseFileManager fileManager, Path path, Path userJarPath) { @@ -220,6 +221,7 @@ * * @param fileManager the file manager creating this file object * @param path the path referred to by this file object + * @return the file object */ public static PathFileObject forJRTPath(BaseFileManager fileManager, final Path path) { @@ -304,6 +306,16 @@ return null; } + @Override @DefinedBy(Api.COMPILER) + public Kind getKind() { + return BaseFileManager.getKind(userPath); + } + + @Override @DefinedBy(Api.COMPILER) + public boolean isNameCompatible(String simpleName, Kind kind) { + return isPathNameCompatible(userPath, simpleName, kind); + } + @Override PathFileObject getSibling(String baseName) { return new SimpleFileObject(fileManager, @@ -369,34 +381,37 @@ @Override @DefinedBy(Api.COMPILER) public Kind getKind() { - return BaseFileManager.getKind(path.getFileName().toString()); + return BaseFileManager.getKind(path); } @Override @DefinedBy(Api.COMPILER) public boolean isNameCompatible(String simpleName, Kind kind) { + return isPathNameCompatible(path, simpleName, kind); + } + + protected boolean isPathNameCompatible(Path p, String simpleName, Kind kind) { Objects.requireNonNull(simpleName); Objects.requireNonNull(kind); - if (kind == Kind.OTHER && getKind() != kind) { + if (kind == Kind.OTHER && BaseFileManager.getKind(p) != kind) { return false; } String sn = simpleName + kind.extension; - String pn = path.getFileName().toString(); + String pn = p.getFileName().toString(); if (pn.equals(sn)) { return true; } - if (path.getFileSystem() == defaultFileSystem) { + if (p.getFileSystem() == defaultFileSystem) { if (isMacOS) { - String name = path.getFileName().toString(); - if (Normalizer.isNormalized(name, Normalizer.Form.NFD) + if (Normalizer.isNormalized(pn, Normalizer.Form.NFD) && Normalizer.isNormalized(sn, Normalizer.Form.NFC)) { // On Mac OS X it is quite possible to have the file name and the // given simple name normalized in different ways. // In that case we have to normalize file name to the // Normal Form Composed (NFC). - String normName = Normalizer.normalize(name, Normalizer.Form.NFC); + String normName = Normalizer.normalize(pn, Normalizer.Form.NFC); if (normName.equals(sn)) { return true; } @@ -406,7 +421,7 @@ if (pn.equalsIgnoreCase(sn)) { try { // allow for Windows - return path.toRealPath(LinkOption.NOFOLLOW_LINKS).getFileName().toString().equals(sn); + return p.toRealPath(LinkOption.NOFOLLOW_LINKS).getFileName().toString().equals(sn); } catch (IOException e) { } } @@ -552,9 +567,12 @@ return (lastDot == -1 ? fileName : fileName.substring(0, lastDot)); } - /** Return the last component of a presumed hierarchical URI. - * From the scheme specific part of the URI, it returns the substring - * after the last "/" if any, or everything if no "/" is found. + /** + * Return the last component of a presumed hierarchical URI. + * From the scheme specific part of the URI, it returns the substring + * after the last "/" if any, or everything if no "/" is found. + * @param fo the file object + * @return the simple name of the file object */ public static String getSimpleName(FileObject fo) { URI uri = fo.toUri(); diff -r 9be30ec2401e -r b8a35541a048 test/tools/javac/file/SymLinkTest.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/tools/javac/file/SymLinkTest.java Thu Apr 20 16:13:40 2017 -0700 @@ -0,0 +1,94 @@ +/* + * Copyright (c) 2014, 2017, 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 + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @bug 8178017 + * @summary JDK 9 change to symlink handling causes misleading + * class.public.should.be.in.file diagnostic + * @library /tools/lib + * @modules jdk.compiler/com.sun.tools.javac.api + * jdk.compiler/com.sun.tools.javac.main + * @build toolbox.JavacTask toolbox.TestRunner toolbox.ToolBox + * @run main SymLinkTest + */ + +import java.io.IOException; +import java.nio.file.FileSystemException; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; + +import toolbox.JavacTask; +import toolbox.TestRunner; +import toolbox.TestRunner.Test; +import toolbox.ToolBox; + +public class SymLinkTest extends TestRunner { + public static void main(String... args) throws Exception { + new SymLinkTest().runTests(m -> new Object[] { Paths.get(m.getName()) }); + } + + private final ToolBox tb = new ToolBox(); + + public SymLinkTest() { + super(System.err); + } + + @Test + public void testgetKind(Path base) throws IOException { + test(base, "SOURCE"); + } + + @Test + public void testSymLink(Path base) throws IOException { + test(base, "SOURCE.java"); + } + + void test(Path base, String name) throws IOException { + Path file = base.resolve(name); + Path javaFile = base.resolve("HelloWorld.java"); + tb.writeFile(file, + "public class HelloWorld {\n" + + " public static void main(String... args) {\n" + + " System.err.println(\"Hello World!\");\n" + + " }\n" + + "}"); + + try { + Files.createSymbolicLink(javaFile, file.getFileName()); + } catch (FileSystemException fse) { + System.err.println("warning: test passes vacuously, sym-link could not be created"); + System.err.println(fse.getMessage()); + return; + } + + Path classes = Files.createDirectories(base.resolve("classes")); + new JavacTask(tb) + .outdir(classes) + .files(javaFile) + .run() + .writeAll(); + } +} +