Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@
import com.sun.tools.javac.code.Types;
import com.sun.tools.javac.tree.JCTree;
import com.sun.tools.javac.util.Name;
import java.util.Objects;
import org.jspecify.annotations.Nullable;

/**
Expand Down Expand Up @@ -133,18 +134,16 @@ private static StaticImportInfo create(
// TODO(gak): we should instead find the most specific subtype with a member that is _used_
Type canonicalOwner = null;
for (Symbol member : members) {
Type owner = types.erasure(member.owner.type);
Type owner = canonicalOwner(member, baseType, types, pkgSym);
if (canonicalOwner == null || types.isSubtype(owner, canonicalOwner)) {
canonicalOwner = owner;
}
}

if (canonicalOwner == null) {
return null;
}

if (members.size() == 1 && getOnlyElement(members) instanceof ClassSymbol) {
return StaticImportInfo.create(access.toString(), getOnlyElement(members).toString());
if (members.size() == 1
&& getOnlyElement(members) instanceof ClassSymbol classSymbol
&& isTypeAccessibleFromPackage(classSymbol, pkgSym)) {
return StaticImportInfo.create(access.toString(), classSymbol.toString());
}
return StaticImportInfo.create(
access.getExpression().toString(),
Expand All @@ -153,6 +152,24 @@ private static StaticImportInfo create(
members);
}

/**
* Finds the most canonical type that owns or inherits {@code member} from {@code baseType} and is
* accessible from {@code pkg}.
*/
private static Type canonicalOwner(
Symbol member, Symbol.TypeSymbol baseType, Types types, Symbol.PackageSymbol pkg) {
Type memberOwner = types.erasure(member.owner.type);
Type owner = types.erasure(baseType.type);
for (Type superType : types.closure(baseType.type)) {
Type erasedSuperType = types.erasure(superType);
if (types.isSubtype(erasedSuperType, memberOwner)
&& isTypeAccessibleFromPackage(erasedSuperType.tsym, pkg)) {
owner = erasedSuperType;
}
}
return owner;
}

/**
* Looks for a field or method with the given {@code identifier}, in {@code typeSym} or one of its
* super-types or super-interfaces, and that is visible from the {@code start} symbol.
Expand Down Expand Up @@ -183,18 +200,8 @@ private static ImmutableSet<Symbol> lookup(
if (!isStatic(member)) {
continue;
}
switch ((int) (member.flags() & Flags.AccessFlags)) {
case Flags.PRIVATE:
continue;
case 0:
case Flags.PROTECTED:
if (enclosingPackage(member).orElse(null) != pkg) {
continue;
}
break;
case Flags.PUBLIC:
default:
break;
if (!isAccessibleFromPackage(member, pkg)) {
continue;
}
if (member.isMemberOf(start, types)) {
members.add(member);
Expand All @@ -204,5 +211,22 @@ private static ImmutableSet<Symbol> lookup(
return members.build();
}

private static boolean isTypeAccessibleFromPackage(Symbol type, Symbol.PackageSymbol pkg) {
for (Symbol curr = type; !(curr instanceof Symbol.PackageSymbol); curr = curr.owner) {
if (!isAccessibleFromPackage(curr, pkg)) {
return false;
}
}
return true;
}

private static boolean isAccessibleFromPackage(Symbol sym, Symbol.PackageSymbol pkg) {
return switch ((int) (sym.flags() & Flags.AccessFlags)) {
case Flags.PRIVATE -> false;
case 0, Flags.PROTECTED -> Objects.equals(enclosingPackage(sym).orElse(null), pkg);
default -> true;
};
}

private StaticImports() {}
}
Loading
Loading