< prev index next >
src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Check.java
Print this page
rev 3467 : [mq]: 8153362
@@ -29,10 +29,12 @@
import javax.tools.JavaFileManager;
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.tree.*;
@@ -3654,6 +3656,163 @@
} catch (CompletionFailure ex) {
return false;
}
}
+ public void checkUnexportedInApi(Env<AttrContext> 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 = lint.augment(tree.sym);
+ if (lint.isEnabled(LintCategory.UNEXPORTED_IN_API)) {
+ super.visitMethodDef(tree);
+ }
+ }
+ @Override
+ public void visitVarDef(JCVariableDecl tree) {
+ if (!isAPISymbol(tree.sym) && tree.sym.owner.kind != MTH)
+ return;
+ lint = lint.augment(tree.sym);
+ if (lint.isEnabled(LintCategory.UNEXPORTED_IN_API)) {
+ scan(tree.mods);
+ scan(tree.vartype);
+ }
+ }
+ @Override
+ public void visitClassDef(JCClassDecl tree) {
+ if (tree != check)
+ return ;
+
+ if (!isAPISymbol(tree.sym))
+ return ;
+
+ lint = lint.augment(tree.sym);
+ if (lint.isEnabled(LintCategory.UNEXPORTED_IN_API)) {
+ scan(tree.mods);
+ scan(tree.typarams);
+ try {
+ inSuperType = true;
+ scan(tree.extending);
+ scan(tree.implementing);
+ } finally {
+ inSuperType = false;
+ }
+ scan(tree.defs);
+ }
+ }
+ @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(pos, "inaccessible.in.api");
+ return ;
+ }
+
+ PackageSymbol whatPackage = what.packge();
+ ExportsDirective whatExport = findExport(whatPackage);
+ ExportsDirective inExport = findExport(inPackage);
+
+ if (whatExport == null) { //package not exported:
+ log.warning(pos, "unexported.in.api");
+ return ;
+ }
+
+ if (whatExport.modules != null) {
+ if (inExport.modules == null || !whatExport.modules.containsAll(inExport.modules)) {
+ log.warning(pos, "unexported.in.api.qualified");
+ }
+ }
+
+ if (whatPackage.modle != inPackage.modle && whatPackage.modle != syms.java_base) {
+ //check that relativeTo.modle requires public what.modle, somehow:
+ List<ModuleSymbol> 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(pos, "unexported.in.api.not.required.public");
+ }
+ }
}
< prev index next >