# HG changeset patch # User jlahoda # Date 1471966930 -7200 # Tue Aug 23 17:42:10 2016 +0200 # Node ID d3aa174aff7ea6b8142cdd24cbe1df7f34a596b1 # Parent 18f3a6037c6b95bd7a98e2d99525a27dde2919cd imported patch 8153362-phase2 diff --git a/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Attr.java b/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Attr.java --- a/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Attr.java +++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Attr.java @@ -4414,6 +4414,7 @@ chk.checkDeprecatedAnnotation(env.tree.pos(), c); chk.checkClassOverrideEqualsAndHashIfNeeded(env.tree.pos(), c); chk.checkFunctionalInterface((JCClassDecl) env.tree, c); + chk.checkLeaksNotAccessible(env, (JCClassDecl) env.tree); } finally { env.info.returnResult = prevReturnRes; log.useSource(prev); diff --git a/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Check.java b/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Check.java --- a/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Check.java +++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Check.java @@ -31,10 +31,13 @@ import com.sun.tools.javac.code.*; import com.sun.tools.javac.code.Attribute.Compound; +import com.sun.tools.javac.code.Directive.ExportsDirective; +import com.sun.tools.javac.code.Directive.RequiresDirective; import com.sun.tools.javac.comp.Annotate.AnnotationTypeMetadata; import com.sun.tools.javac.jvm.*; import com.sun.tools.javac.resources.CompilerProperties.Errors; import com.sun.tools.javac.resources.CompilerProperties.Fragments; +import com.sun.tools.javac.resources.CompilerProperties.Warnings; import com.sun.tools.javac.tree.*; import com.sun.tools.javac.util.*; import com.sun.tools.javac.util.JCDiagnostic.DiagnosticFlag; @@ -3669,4 +3672,178 @@ } } + public void checkLeaksNotAccessible(Env env, JCClassDecl check) { + JCCompilationUnit toplevel = env.toplevel; + + if ( toplevel.modle == syms.unnamedModule + || toplevel.modle == syms.noModule + || (check.sym.flags() & COMPOUND) != 0) { + return ; + } + + ExportsDirective currentExport = findExport(toplevel.packge); + + if ( currentExport == null //not exported + || currentExport.modules != null) //don't check classes in qualified export + return ; + + new TreeScanner() { + Lint lint = env.info.lint; + boolean inSuperType; + + @Override + public void visitBlock(JCBlock tree) { + } + @Override + public void visitMethodDef(JCMethodDecl tree) { + if (!isAPISymbol(tree.sym)) + return; + Lint prevLint = lint; + try { + lint = lint.augment(tree.sym); + if (lint.isEnabled(LintCategory.EXPORTS)) { + super.visitMethodDef(tree); + } + } finally { + lint = prevLint; + } + } + @Override + public void visitVarDef(JCVariableDecl tree) { + if (!isAPISymbol(tree.sym) && tree.sym.owner.kind != MTH) + return; + Lint prevLint = lint; + try { + lint = lint.augment(tree.sym); + if (lint.isEnabled(LintCategory.EXPORTS)) { + scan(tree.mods); + scan(tree.vartype); + } + } finally { + lint = prevLint; + } + } + @Override + public void visitClassDef(JCClassDecl tree) { + if (tree != check) + return ; + + if (!isAPISymbol(tree.sym)) + return ; + + Lint prevLint = lint; + try { + lint = lint.augment(tree.sym); + if (lint.isEnabled(LintCategory.EXPORTS)) { + scan(tree.mods); + scan(tree.typarams); + try { + inSuperType = true; + scan(tree.extending); + scan(tree.implementing); + } finally { + inSuperType = false; + } + scan(tree.defs); + } + } finally { + lint = prevLint; + } + } + @Override + public void visitTypeApply(JCTypeApply tree) { + scan(tree.clazz); + boolean oldInSuperType = inSuperType; + try { + inSuperType = false; + scan(tree.arguments); + } finally { + inSuperType = oldInSuperType; + } + } + @Override + public void visitIdent(JCIdent tree) { + Symbol sym = TreeInfo.symbol(tree); + if (sym.kind == TYP && !sym.type.hasTag(TYPEVAR)) { + checkVisible(tree.pos(), sym, toplevel.packge, inSuperType); + } + } + + @Override + public void visitSelect(JCFieldAccess tree) { + Symbol sym = TreeInfo.symbol(tree); + Symbol sitesym = TreeInfo.symbol(tree.selected); + if (sym.kind == TYP && sitesym.kind == PCK) { + checkVisible(tree.pos(), sym, toplevel.packge, inSuperType); + } else { + super.visitSelect(tree); + } + } + + @Override + public void visitAnnotation(JCAnnotation tree) { + if (tree.attribute.type.tsym.getAnnotation(java.lang.annotation.Documented.class) != null) + super.visitAnnotation(tree); + } + + }.scan(check); + } + //where: + private ExportsDirective findExport(PackageSymbol pack) { + for (ExportsDirective d : pack.modle.exports) { + if (d.packge == pack) + return d; + } + + return null; + } + private boolean isAPISymbol(Symbol sym) { + while (sym.kind != PCK) { + if ((sym.flags() & Flags.PUBLIC) == 0 && (sym.flags() & Flags.PROTECTED) == 0) { + return false; + } + sym = sym.owner; + } + return true; + } + private void checkVisible(DiagnosticPosition pos, Symbol what, PackageSymbol inPackage, boolean inSuperType) { + if (!isAPISymbol(what) && !inSuperType) { //package private/private element + log.warning(LintCategory.EXPORTS, pos, Warnings.LeaksNotAccessible(kindName(what), what, what.packge().modle)); + return ; + } + + PackageSymbol whatPackage = what.packge(); + ExportsDirective whatExport = findExport(whatPackage); + ExportsDirective inExport = findExport(inPackage); + + if (whatExport == null) { //package not exported: + log.warning(LintCategory.EXPORTS, pos, Warnings.LeaksNotAccessibleUnexported(kindName(what), what, what.packge().modle)); + return ; + } + + if (whatExport.modules != null) { + if (inExport.modules == null || !whatExport.modules.containsAll(inExport.modules)) { + log.warning(LintCategory.EXPORTS, pos, Warnings.LeaksNotAccessibleUnexportedQualified(kindName(what), what, what.packge().modle)); + } + } + + if (whatPackage.modle != inPackage.modle && whatPackage.modle != syms.java_base) { + //check that relativeTo.modle requires public what.modle, somehow: + List todo = List.of(inPackage.modle); + + while (todo.nonEmpty()) { + ModuleSymbol current = todo.head; + todo = todo.tail; + if (current == whatPackage.modle) + return ; //OK + for (RequiresDirective req : current.requires) { + if (req.isPublic()) { + todo = todo.prepend(req.module); + } + } + } + + log.warning(LintCategory.EXPORTS, pos, Warnings.LeaksNotAccessibleNotRequiredPublic(kindName(what), what, what.packge().modle)); + } + } } diff --git a/src/jdk.compiler/share/classes/com/sun/tools/javac/resources/compiler.properties b/src/jdk.compiler/share/classes/com/sun/tools/javac/resources/compiler.properties --- a/src/jdk.compiler/share/classes/com/sun/tools/javac/resources/compiler.properties +++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/resources/compiler.properties @@ -2857,6 +2857,19 @@ compiler.warn.service.provided.but.not.exported.or.used=\ service interface provided but not exported or used +# 0: kind name, 1: symbol, 2: symbol +compiler.warn.leaks.not.accessible=\ + {0} {1} in module {2} is not accessible to clients that require this module +# 0: kind name, 1: symbol, 2: symbol +compiler.warn.leaks.not.accessible.unexported=\ + {0} {1} in module {2} is not exported +# 0: kind name, 1: symbol, 2: symbol +compiler.warn.leaks.not.accessible.not.required.public=\ + {0} {1} in module {2} is not indirectly exported using 'requires public' +# 0: kind name, 1: symbol, 2: symbol +compiler.warn.leaks.not.accessible.unexported.qualified=\ + {0} {1} in module {2} may not be visible to all clients that require this module + ### # errors related to options diff --git a/test/tools/javac/diags/examples/LeaksNotAccessible/LeaksNotAccessible.java b/test/tools/javac/diags/examples/LeaksNotAccessible/LeaksNotAccessible.java new file mode 100644 --- /dev/null +++ b/test/tools/javac/diags/examples/LeaksNotAccessible/LeaksNotAccessible.java @@ -0,0 +1,25 @@ +/* + * Copyright (c) 2016, 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. + */ + +// key: compiler.warn.leaks.not.accessible +// options: -Xlint:exports diff --git a/test/tools/javac/diags/examples/LeaksNotAccessible/modulesourcepath/m1/api/Api.java b/test/tools/javac/diags/examples/LeaksNotAccessible/modulesourcepath/m1/api/Api.java new file mode 100644 --- /dev/null +++ b/test/tools/javac/diags/examples/LeaksNotAccessible/modulesourcepath/m1/api/Api.java @@ -0,0 +1,32 @@ +/* + * Copyright (c) 2016, 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. + */ + +package api; + +public class Api { + public Impl getImpl() { + return null; + } +} + +class Impl {} diff --git a/test/tools/javac/diags/examples/LeaksNotAccessible/modulesourcepath/m1/module-info.java b/test/tools/javac/diags/examples/LeaksNotAccessible/modulesourcepath/m1/module-info.java new file mode 100644 --- /dev/null +++ b/test/tools/javac/diags/examples/LeaksNotAccessible/modulesourcepath/m1/module-info.java @@ -0,0 +1,26 @@ +/* + * Copyright (c) 2016, 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. + */ + +module m1 { + exports api; +} diff --git a/test/tools/javac/diags/examples/LeaksNotAccessibleNotRequiredPublic/LeaksNotAccessibleNotRequiredPublic.java b/test/tools/javac/diags/examples/LeaksNotAccessibleNotRequiredPublic/LeaksNotAccessibleNotRequiredPublic.java new file mode 100644 --- /dev/null +++ b/test/tools/javac/diags/examples/LeaksNotAccessibleNotRequiredPublic/LeaksNotAccessibleNotRequiredPublic.java @@ -0,0 +1,25 @@ +/* + * Copyright (c) 2016, 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. + */ + +// key: compiler.warn.leaks.not.accessible.not.required.public +// options: -Xlint:exports diff --git a/test/tools/javac/diags/examples/LeaksNotAccessibleNotRequiredPublic/modulesourcepath/m1/api1/Api1.java b/test/tools/javac/diags/examples/LeaksNotAccessibleNotRequiredPublic/modulesourcepath/m1/api1/Api1.java new file mode 100644 --- /dev/null +++ b/test/tools/javac/diags/examples/LeaksNotAccessibleNotRequiredPublic/modulesourcepath/m1/api1/Api1.java @@ -0,0 +1,27 @@ +/* + * Copyright (c) 2016, 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. + */ + +package api1; + +public class Api1 { +} diff --git a/test/tools/javac/diags/examples/LeaksNotAccessibleNotRequiredPublic/modulesourcepath/m1/module-info.java b/test/tools/javac/diags/examples/LeaksNotAccessibleNotRequiredPublic/modulesourcepath/m1/module-info.java new file mode 100644 --- /dev/null +++ b/test/tools/javac/diags/examples/LeaksNotAccessibleNotRequiredPublic/modulesourcepath/m1/module-info.java @@ -0,0 +1,26 @@ +/* + * Copyright (c) 2016, 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. + */ + +module m1 { + exports api1; +} diff --git a/test/tools/javac/diags/examples/LeaksNotAccessibleNotRequiredPublic/modulesourcepath/m2/api2/Api2.java b/test/tools/javac/diags/examples/LeaksNotAccessibleNotRequiredPublic/modulesourcepath/m2/api2/Api2.java new file mode 100644 --- /dev/null +++ b/test/tools/javac/diags/examples/LeaksNotAccessibleNotRequiredPublic/modulesourcepath/m2/api2/Api2.java @@ -0,0 +1,30 @@ +/* + * Copyright (c) 2016, 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. + */ + +package api2; + +public class Api2 { + public api1.Api1 getApi1() { + return null; + } +} diff --git a/test/tools/javac/diags/examples/LeaksNotAccessibleNotRequiredPublic/modulesourcepath/m2/module-info.java b/test/tools/javac/diags/examples/LeaksNotAccessibleNotRequiredPublic/modulesourcepath/m2/module-info.java new file mode 100644 --- /dev/null +++ b/test/tools/javac/diags/examples/LeaksNotAccessibleNotRequiredPublic/modulesourcepath/m2/module-info.java @@ -0,0 +1,27 @@ +/* + * Copyright (c) 2016, 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. + */ + +module m2 { + requires m1; + exports api2; +} diff --git a/test/tools/javac/diags/examples/LeaksNotAccessibleUnexported/LeaksNotAccessibleUnexported.java b/test/tools/javac/diags/examples/LeaksNotAccessibleUnexported/LeaksNotAccessibleUnexported.java new file mode 100644 --- /dev/null +++ b/test/tools/javac/diags/examples/LeaksNotAccessibleUnexported/LeaksNotAccessibleUnexported.java @@ -0,0 +1,25 @@ +/* + * Copyright (c) 2016, 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. + */ + +// key: compiler.warn.leaks.not.accessible.unexported +// options: -Xlint:exports diff --git a/test/tools/javac/diags/examples/LeaksNotAccessibleUnexported/modulesourcepath/m1/api/Api.java b/test/tools/javac/diags/examples/LeaksNotAccessibleUnexported/modulesourcepath/m1/api/Api.java new file mode 100644 --- /dev/null +++ b/test/tools/javac/diags/examples/LeaksNotAccessibleUnexported/modulesourcepath/m1/api/Api.java @@ -0,0 +1,30 @@ +/* + * Copyright (c) 2016, 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. + */ + +package api; + +public class Api { + public impl.Impl getImpl() { + return null; + } +} diff --git a/test/tools/javac/diags/examples/LeaksNotAccessibleUnexported/modulesourcepath/m1/impl/Impl.java b/test/tools/javac/diags/examples/LeaksNotAccessibleUnexported/modulesourcepath/m1/impl/Impl.java new file mode 100644 --- /dev/null +++ b/test/tools/javac/diags/examples/LeaksNotAccessibleUnexported/modulesourcepath/m1/impl/Impl.java @@ -0,0 +1,27 @@ +/* + * Copyright (c) 2016, 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. + */ + +package impl; + +public class Impl { +} diff --git a/test/tools/javac/diags/examples/LeaksNotAccessibleUnexported/modulesourcepath/m1/module-info.java b/test/tools/javac/diags/examples/LeaksNotAccessibleUnexported/modulesourcepath/m1/module-info.java new file mode 100644 --- /dev/null +++ b/test/tools/javac/diags/examples/LeaksNotAccessibleUnexported/modulesourcepath/m1/module-info.java @@ -0,0 +1,26 @@ +/* + * Copyright (c) 2016, 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. + */ + +module m1 { + exports api; +} diff --git a/test/tools/javac/diags/examples/LeaksNotAccessibleUnexportedQualified/LeaksNotAccessibleUnexportedQualified.java b/test/tools/javac/diags/examples/LeaksNotAccessibleUnexportedQualified/LeaksNotAccessibleUnexportedQualified.java new file mode 100644 --- /dev/null +++ b/test/tools/javac/diags/examples/LeaksNotAccessibleUnexportedQualified/LeaksNotAccessibleUnexportedQualified.java @@ -0,0 +1,25 @@ +/* + * Copyright (c) 2016, 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. + */ + +// key: compiler.warn.leaks.not.accessible.unexported.qualified +// options: -Xlint:exports diff --git a/test/tools/javac/diags/examples/LeaksNotAccessibleUnexportedQualified/modulesourcepath/m1/api/Api.java b/test/tools/javac/diags/examples/LeaksNotAccessibleUnexportedQualified/modulesourcepath/m1/api/Api.java new file mode 100644 --- /dev/null +++ b/test/tools/javac/diags/examples/LeaksNotAccessibleUnexportedQualified/modulesourcepath/m1/api/Api.java @@ -0,0 +1,30 @@ +/* + * Copyright (c) 2016, 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. + */ + +package api; + +public class Api { + public qapi.QApi get() { + return null; + } +} diff --git a/test/tools/javac/diags/examples/LeaksNotAccessibleUnexportedQualified/modulesourcepath/m1/module-info.java b/test/tools/javac/diags/examples/LeaksNotAccessibleUnexportedQualified/modulesourcepath/m1/module-info.java new file mode 100644 --- /dev/null +++ b/test/tools/javac/diags/examples/LeaksNotAccessibleUnexportedQualified/modulesourcepath/m1/module-info.java @@ -0,0 +1,27 @@ +/* + * Copyright (c) 2016, 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. + */ + +module m1 { + exports api; + exports qapi to m2; +} diff --git a/test/tools/javac/diags/examples/LeaksNotAccessibleUnexportedQualified/modulesourcepath/m1/qapi/QApi.java b/test/tools/javac/diags/examples/LeaksNotAccessibleUnexportedQualified/modulesourcepath/m1/qapi/QApi.java new file mode 100644 --- /dev/null +++ b/test/tools/javac/diags/examples/LeaksNotAccessibleUnexportedQualified/modulesourcepath/m1/qapi/QApi.java @@ -0,0 +1,27 @@ +/* + * Copyright (c) 2016, 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. + */ + +package qapi; + +public class QApi { +} diff --git a/test/tools/javac/diags/examples/LeaksNotAccessibleUnexportedQualified/modulesourcepath/m2/module-info.java b/test/tools/javac/diags/examples/LeaksNotAccessibleUnexportedQualified/modulesourcepath/m2/module-info.java new file mode 100644 --- /dev/null +++ b/test/tools/javac/diags/examples/LeaksNotAccessibleUnexportedQualified/modulesourcepath/m2/module-info.java @@ -0,0 +1,26 @@ +/* + * Copyright (c) 2016, 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. + */ + +module m2 { + requires m1; +} diff --git a/test/tools/javac/modules/ExportsUnexported.java b/test/tools/javac/modules/ExportsUnexported.java new file mode 100644 --- /dev/null +++ b/test/tools/javac/modules/ExportsUnexported.java @@ -0,0 +1,375 @@ +/* + * Copyright (c) 2016, 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 + * @summary tests for module declarations + * @library /tools/lib + * @modules jdk.compiler/com.sun.tools.javac.api + * jdk.compiler/com.sun.tools.javac.main + * @build toolbox.ToolBox toolbox.JavacTask ModuleTestBase + * @run main ExportsUnexported + */ + +import java.nio.file.Path; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collections; +import java.util.List; + +import toolbox.JavacTask; +import toolbox.Task; + +public class ExportsUnexported extends ModuleTestBase { + + public static void main(String... args) throws Exception { + ExportsUnexported t = new ExportsUnexported(); + t.runTests(); + } + + @Test + public void testLocations(Path base) throws Exception { + String warningsTest = "package api;\n" + + "import impl.impl.*;\n" + + "@impl.impl^.DocAnn\n" + + "public abstract class Api extends impl.impl^.Cls implements impl.impl^.Intf, impl.impl^.NonDocAnn, impl.impl^.DocAnn {\n" + + " public static impl.impl^.Cls m(impl.impl^.Intf i, impl.impl^.Cls c) throws impl.impl^.Exc { return null; }\n" + + " public static impl.impl^.Cls f;\n" + + "}"; + String noWarningsTest = "package api;\n" + + "import impl.impl.*;\n" + + "@impl.impl.NonDocAnn\n" + + "public abstract class Api {\n" + + " private static abstract class I extends impl.impl.Cls implements impl.impl.Intf, impl.impl.NonDocAnn, impl.impl.DocAnn {\n" + + " public static abstract class II extends impl.impl.Cls implements impl.impl.Intf, impl.impl.NonDocAnn, impl.impl.DocAnn { }\n" + + " public static impl.impl.Cls m(impl.impl.Intf i, impl.impl.Cls c) throws impl.impl.Exc { return null; }\n" + + " public static impl.impl.Cls f;\n" + + " }\n" + + " private static impl.impl.Cls m(impl.impl.Intf i, impl.impl.Cls c) throws impl.impl.Exc { return null; }\n" + + " private static impl.impl.Cls f1;\n" + + " public static void m() { new impl.impl.Cls(); }\n" + + " public static Object f2 = new impl.impl.Cls();\n" + + "}"; + for (String genericTest : new String[] {warningsTest, noWarningsTest}) { + for (String test : new String[] {genericTest, genericTest.replaceAll("impl\\.impl\\^.([A-Za-z])", "^$1").replaceAll("impl\\.impl\\.([A-Za-z])", "$1")}) { + System.err.println("testing: " + test); + + Path src = base.resolve("src"); + Path src_m1 = src.resolve("m1"); + StringBuilder testCode = new StringBuilder(); + List expectedLog = new ArrayList<>(); + int line = 1; + int col = 1; + + for (int i = 0; i < test.length(); i++) { + char c = test.charAt(i); + + if (c == '^') { + StringBuilder typeName = new StringBuilder(); + for (int j = i + 1 + (test.charAt(i + 1) == '.' ? 1 : 0); + j < test.length() && Character.isJavaIdentifierPart(test.charAt(j)); + j++) { + typeName.append(test.charAt(j)); + } + String kindName; + switch (typeName.toString()) { + case "Exc": case "DocAnn": case "NonDocAnn": + case "Cls": kindName = "kindname.class"; break; + case "Intf": kindName = "kindname.interface"; break; + default: + throw new AssertionError(typeName.toString()); + } + expectedLog.add("Api.java:" + line + ":" + col + ": compiler.warn.leaks.not.accessible.unexported: " + kindName + ", impl.impl." + typeName + ", m1"); + continue; + } + + if (c == '\n') { + line++; + col = 0; + } + + testCode.append(c); + col++; + } + + if (!expectedLog.isEmpty()) { + expectedLog.add("" + expectedLog.size() + " warning" + (expectedLog.size() == 1 ? "" : "s")); + expectedLog.add("- compiler.err.warnings.and.werror"); + expectedLog.add("1 error"); + } + + Collections.sort(expectedLog); + + tb.writeJavaFiles(src_m1, + "module m1 { exports api; }", + testCode.toString(), + "package impl.impl; public class Cls { }", + "package impl.impl; public class Exc extends Exception { }", + "package impl.impl; public interface Intf { }", + "package impl.impl; @java.lang.annotation.Documented public @interface DocAnn { }", + "package impl.impl; public @interface NonDocAnn { }"); + Path classes = base.resolve("classes"); + tb.createDirectories(classes); + + List log = new JavacTask(tb) + .options("-XDrawDiagnostics", + "-Werror", + "-modulesourcepath", src.toString(), + "-Xlint:exports") + .outdir(classes) + .files(findJavaFiles(src)) + .run(expectedLog.isEmpty() ? Task.Expect.SUCCESS : Task.Expect.FAIL) + .writeAll() + .getOutputLines(Task.OutputKind.DIRECT); + + log = new ArrayList<>(log); + Collections.sort(log); + + if (expectedLog.isEmpty() ? !log.equals(Arrays.asList("")) : !log.equals(expectedLog)) { + throw new Exception("expected output not found in: " + log + "; " + expectedLog); + } + } + } + } + + @Test + public void testAccessibleToSpecificOrAll(Path base) throws Exception { + Path src = base.resolve("src"); + Path src_lib1 = src.resolve("lib1"); + tb.writeJavaFiles(src_lib1, + "module lib1 { exports lib1; }", + "package lib1; public class Lib1 {}"); + Path src_lib2 = src.resolve("lib2"); + tb.writeJavaFiles(src_lib2, + "module lib2 { exports lib2; }", + "package lib2; public class Lib2 {}"); + Path src_api = src.resolve("api"); + tb.writeJavaFiles(src_api, + "module api {\n" + + " exports api;\n" + + " exports qapi1 to qual1;\n" + + " exports qapi2 to qual1, qual2;\n" + + " requires public lib1;\n" + + " requires lib2;\n" + + "}\n", + "package api;\n" + + "public class Api {\n" + + " public lib1.Lib1 lib1;\n" + + " public lib2.Lib2 lib2;\n" + + " public qapi1.QApi1 qapi1;\n" + + " public impl.Impl impl;\n" + + "}", + "package qapi1;\n" + + "public class QApi1 {\n" + + " public qapi2.QApi2 qapi2;\n" + + "}", + "package qapi2;\n" + + "public class QApi2 {\n" + + " public qapi1.QApi1 qapi1;\n" + + "}", + "package impl;\n" + + "public class Impl {\n" + + "}"); + Path src_qual1 = src.resolve("qual1"); + tb.writeJavaFiles(src_qual1, "module qual1 { }"); + Path src_qual2 = src.resolve("qual2"); + tb.writeJavaFiles(src_qual2, "module qual2 { }"); + Path classes = base.resolve("classes"); + tb.createDirectories(classes); + + List log = new JavacTask(tb) + .options("-XDrawDiagnostics", + "-Werror", + "-modulesourcepath", src.toString(), + "-Xlint:exports") + .outdir(classes) + .files(findJavaFiles(src)) + .run(Task.Expect.FAIL) + .writeAll() + .getOutputLines(Task.OutputKind.DIRECT); + + List expected = Arrays.asList( + "Api.java:4:16: compiler.warn.leaks.not.accessible.not.required.public: kindname.class, lib2.Lib2, lib2", + "Api.java:5:17: compiler.warn.leaks.not.accessible.unexported.qualified: kindname.class, qapi1.QApi1, api", + "Api.java:6:16: compiler.warn.leaks.not.accessible.unexported: kindname.class, impl.Impl, api", + "- compiler.err.warnings.and.werror", + "1 error", + "3 warnings" + ); + + if (!log.equals(expected)) + throw new Exception("expected output not found"); + } + + @Test + public void testNestedClasses(Path base) throws Exception { + Path src = base.resolve("src"); + Path src_api = src.resolve("api"); + tb.writeJavaFiles(src_api, + "module api {\n" + + " exports api;\n" + + "}\n", + "package api;\n" + + "import impl.Impl.Nested;\n" + + "public class Api {\n" + + " public impl.Impl impl1;\n" + + " public impl.Impl.Nested impl2;\n" + + " public Nested impl3;\n" + + "}", + "package impl;\n" + + "public class Impl {\n" + + " public static class Nested {\n" + + " }\n" + + "}"); + Path classes = base.resolve("classes"); + tb.createDirectories(classes); + + List log = new JavacTask(tb) + .options("-XDrawDiagnostics", + "-Werror", + "-modulesourcepath", src.toString(), + "-Xlint:exports") + .outdir(classes) + .files(findJavaFiles(src)) + .run(Task.Expect.FAIL) + .writeAll() + .getOutputLines(Task.OutputKind.DIRECT); + + List expected = Arrays.asList( + "Api.java:4:16: compiler.warn.leaks.not.accessible.unexported: kindname.class, impl.Impl, api", + "Api.java:5:16: compiler.warn.leaks.not.accessible.unexported: kindname.class, impl.Impl, api", + "Api.java:6:12: compiler.warn.leaks.not.accessible.unexported: kindname.class, impl.Impl.Nested, api", + "- compiler.err.warnings.and.werror", + "1 error", + "3 warnings" + ); + + if (!log.equals(expected)) + throw new Exception("expected output not found"); + } + + @Test + public void testProtectedAndInaccessible(Path base) throws Exception { + Path src = base.resolve("src"); + Path src_api = src.resolve("api"); + tb.writeJavaFiles(src_api, + "module api {\n" + + " exports api;\n" + + "}\n", + "package api;\n" + + "public class Api extends PackagePrivateClass implements PackagePrivateInterface {\n" + + " protected PackagePrivateClass f1;\n" + + " protected PackagePrivateInterface f2;\n" + + " protected Inner f3;\n" + + " protected PrivateInner f4;\n" + + " protected impl.Impl f5;\n" + + " public static class InnerClass extends PrivateInner {}\n" + + " protected static class Inner {}\n" + + " private static class PrivateInner {}\n" + + "}\n" + + "class PackagePrivateClass {}\n" + + "interface PackagePrivateInterface {}", + "package impl;\n" + + "public class Impl {\n" + + "}"); + Path classes = base.resolve("classes"); + tb.createDirectories(classes); + + List log = new JavacTask(tb) + .options("-XDrawDiagnostics", + "-Werror", + "-modulesourcepath", src.toString(), + "-Xlint:exports") + .outdir(classes) + .files(findJavaFiles(src)) + .run(Task.Expect.FAIL) + .writeAll() + .getOutputLines(Task.OutputKind.DIRECT); + + List expected = Arrays.asList( + "Api.java:2:46: compiler.warn.leaks.not.accessible: kindname.interface, api.PackagePrivateInterface, api", + "Api.java:2:106: compiler.warn.leaks.not.accessible: kindname.class, api.PackagePrivateClass, api", + "Api.java:3:15: compiler.warn.leaks.not.accessible: kindname.class, api.PackagePrivateClass, api", + "Api.java:4:15: compiler.warn.leaks.not.accessible: kindname.interface, api.PackagePrivateInterface, api", + "Api.java:6:15: compiler.warn.leaks.not.accessible: kindname.class, api.Api.PrivateInner, api", + "Api.java:7:19: compiler.warn.leaks.not.accessible.unexported: kindname.class, impl.Impl, api", + "- compiler.err.warnings.and.werror", + "1 error", + "6 warnings" + ); + + if (!log.equals(expected)) + throw new Exception("expected output not found"); + } + + @Test + public void testSuppressResetProperly(Path base) throws Exception { + Path src = base.resolve("src"); + Path src_api = src.resolve("api"); + tb.writeJavaFiles(src_api, + "module api {\n" + + " exports api;\n" + + "}\n", + "package api;\n" + + "public class Api {\n" + + " @SuppressWarnings(\"exports\")\n" + + " public PackagePrivateClass f1;\n" + + " public PackagePrivateClass f2;\n" + + " @SuppressWarnings(\"exports\")\n" + + " public void t() {}\n" + + " public PackagePrivateClass f3;\n" + + " @SuppressWarnings(\"exports\")\n" + + " public static class C {\n" + + " public PackagePrivateClass f4;\n" + + " }\n" + + " public PackagePrivateClass f5;\n" + + "}\n" + + "class PackagePrivateClass {}\n"); + Path classes = base.resolve("classes"); + tb.createDirectories(classes); + + List log = new JavacTask(tb) + .options("-XDrawDiagnostics", + "-Werror", + "-modulesourcepath", src.toString(), + "-Xlint:exports") + .outdir(classes) + .files(findJavaFiles(src)) + .run(Task.Expect.FAIL) + .writeAll() + .getOutputLines(Task.OutputKind.DIRECT); + + List expected = Arrays.asList( + "Api.java:5:12: compiler.warn.leaks.not.accessible: kindname.class, api.PackagePrivateClass, api", + "Api.java:8:12: compiler.warn.leaks.not.accessible: kindname.class, api.PackagePrivateClass, api", + "Api.java:13:12: compiler.warn.leaks.not.accessible: kindname.class, api.PackagePrivateClass, api", + "- compiler.err.warnings.and.werror", + "1 error", + "3 warnings" + ); + + if (!log.equals(expected)) + throw new Exception("expected output not found"); + } + +}