diff --git a/common/src/main/java/com/google/auto/common/Visibility.java b/common/src/main/java/com/google/auto/common/Visibility.java index 2719bb017c..45626e3b9e 100644 --- a/common/src/main/java/com/google/auto/common/Visibility.java +++ b/common/src/main/java/com/google/auto/common/Visibility.java @@ -76,4 +76,43 @@ public static Visibility effectiveVisibilityOfElement(Element element) { } return effectiveVisibility; } -} \ No newline at end of file + + /** + * Returns whether the given element is visible from another element in the given package. + */ + public static boolean isVisibleFrom(Element element, PackageElement from) { + switch (effectiveVisibilityOfElement(element)) { + case PUBLIC: + return true; + case PROTECTED: + case DEFAULT: + return MoreElements.getPackage(element).equals(from); + case PRIVATE: + return false; + default: + throw new AssertionError(); + } + } + + /** + * Returns whether the given element is visible from another element in the given package, + * assuming that other element is a subclass (or a member of a subclass) of the former (or + * its enclosing type). + * + *

This is similar to {@link #isVisibleFrom(Element, PackageElement)} except for the + * treatment of {@code protected} elements. + */ + public static boolean isVisibleFromSubclass(Element element, PackageElement from) { + switch (effectiveVisibilityOfElement(element)) { + case PUBLIC: + case PROTECTED: + return true; + case DEFAULT: + return MoreElements.getPackage(element).equals(from); + case PRIVATE: + return false; + default: + throw new AssertionError(); + } + } +} diff --git a/common/src/test/java/com/google/auto/common/VisibilityTest.java b/common/src/test/java/com/google/auto/common/VisibilityTest.java index 34d159ed9c..91591a03a7 100644 --- a/common/src/test/java/com/google/auto/common/VisibilityTest.java +++ b/common/src/test/java/com/google/auto/common/VisibilityTest.java @@ -16,6 +16,7 @@ package com.google.auto.common; import com.google.testing.compile.CompilationRule; +import javax.lang.model.element.PackageElement; import org.junit.Rule; import org.junit.Test; import org.junit.runner.RunWith; @@ -26,6 +27,8 @@ import static com.google.auto.common.Visibility.PROTECTED; import static com.google.auto.common.Visibility.PUBLIC; import static com.google.common.truth.Truth.assertThat; +import static org.junit.Assert.assertTrue; +import static org.junit.Assert.assertFalse; @RunWith(JUnit4.class) public class VisibilityTest { @@ -141,4 +144,124 @@ private Visibility effectiveVisiblityOfClass(Class clazz) { return Visibility.effectiveVisibilityOfElement( compilation.getElements().getTypeElement(clazz.getCanonicalName())); } + + @Test + public void visibilityFrom() { + PackageElement samePackage = compilation.getElements().getPackageElement("com.google.auto.common"); + assertTrue(isVisibleFromClass(PublicClass.class, samePackage)); + assertTrue(isVisibleFromClass(ProtectedClass.class, samePackage)); + assertTrue(isVisibleFromClass(DefaultClass.class, samePackage)); + assertFalse(isVisibleFromClass(PrivateClass.class, samePackage)); + + assertTrue(isVisibleFromClass(PublicClass.NestedPublicClass.class, samePackage)); + assertTrue(isVisibleFromClass(PublicClass.NestedProtectedClass.class, samePackage)); + assertTrue(isVisibleFromClass(PublicClass.NestedDefaultClass.class, samePackage)); + assertFalse(isVisibleFromClass(PublicClass.NestedPrivateClass.class, samePackage)); + + assertTrue(isVisibleFromClass(ProtectedClass.NestedPublicClass.class, samePackage)); + assertTrue(isVisibleFromClass(ProtectedClass.NestedProtectedClass.class, samePackage)); + assertTrue(isVisibleFromClass(ProtectedClass.NestedDefaultClass.class, samePackage)); + assertFalse(isVisibleFromClass(ProtectedClass.NestedPrivateClass.class, samePackage)); + + assertTrue(isVisibleFromClass(DefaultClass.NestedPublicClass.class, samePackage)); + assertTrue(isVisibleFromClass(DefaultClass.NestedProtectedClass.class, samePackage)); + assertTrue(isVisibleFromClass(DefaultClass.NestedDefaultClass.class, samePackage)); + assertFalse(isVisibleFromClass(DefaultClass.NestedPrivateClass.class, samePackage)); + + assertFalse(isVisibleFromClass(PrivateClass.NestedPublicClass.class, samePackage)); + assertFalse(isVisibleFromClass(PrivateClass.NestedProtectedClass.class, samePackage)); + assertFalse(isVisibleFromClass(PrivateClass.NestedDefaultClass.class, samePackage)); + assertFalse(isVisibleFromClass(PrivateClass.NestedPrivateClass.class, samePackage)); + + PackageElement otherPackage = compilation.getElements().getPackageElement("com.example"); + assertTrue(isVisibleFromClass(PublicClass.class, otherPackage)); + assertFalse(isVisibleFromClass(ProtectedClass.class, otherPackage)); + assertFalse(isVisibleFromClass(DefaultClass.class, otherPackage)); + assertFalse(isVisibleFromClass(PrivateClass.class, otherPackage)); + + assertTrue(isVisibleFromClass(PublicClass.NestedPublicClass.class, otherPackage)); + assertFalse(isVisibleFromClass(PublicClass.NestedProtectedClass.class, otherPackage)); + assertFalse(isVisibleFromClass(PublicClass.NestedDefaultClass.class, otherPackage)); + assertFalse(isVisibleFromClass(PublicClass.NestedPrivateClass.class, otherPackage)); + + assertFalse(isVisibleFromClass(ProtectedClass.NestedPublicClass.class, otherPackage)); + assertFalse(isVisibleFromClass(ProtectedClass.NestedProtectedClass.class, otherPackage)); + assertFalse(isVisibleFromClass(ProtectedClass.NestedDefaultClass.class, otherPackage)); + assertFalse(isVisibleFromClass(ProtectedClass.NestedPrivateClass.class, otherPackage)); + + assertFalse(isVisibleFromClass(DefaultClass.NestedPublicClass.class, otherPackage)); + assertFalse(isVisibleFromClass(DefaultClass.NestedProtectedClass.class, otherPackage)); + assertFalse(isVisibleFromClass(DefaultClass.NestedDefaultClass.class, otherPackage)); + assertFalse(isVisibleFromClass(DefaultClass.NestedPrivateClass.class, otherPackage)); + + assertFalse(isVisibleFromClass(PrivateClass.NestedPublicClass.class, otherPackage)); + assertFalse(isVisibleFromClass(PrivateClass.NestedProtectedClass.class, otherPackage)); + assertFalse(isVisibleFromClass(PrivateClass.NestedDefaultClass.class, otherPackage)); + assertFalse(isVisibleFromClass(PrivateClass.NestedPrivateClass.class, otherPackage)); + } + + private boolean isVisibleFromClass(Class clazz, PackageElement from) { + return Visibility.isVisibleFrom( + compilation.getElements().getTypeElement(clazz.getCanonicalName()), from); + } + + @Test + public void visibilityFromSubclass() { + PackageElement samePackage = compilation.getElements().getPackageElement("com.google.auto.common"); + assertTrue(isVisibleFromSubclass(PublicClass.class, samePackage)); + assertTrue(isVisibleFromSubclass(ProtectedClass.class, samePackage)); + assertTrue(isVisibleFromSubclass(DefaultClass.class, samePackage)); + assertFalse(isVisibleFromSubclass(PrivateClass.class, samePackage)); + + assertTrue(isVisibleFromSubclass(PublicClass.NestedPublicClass.class, samePackage)); + assertTrue(isVisibleFromSubclass(PublicClass.NestedProtectedClass.class, samePackage)); + assertTrue(isVisibleFromSubclass(PublicClass.NestedDefaultClass.class, samePackage)); + assertFalse(isVisibleFromSubclass(PublicClass.NestedPrivateClass.class, samePackage)); + + assertTrue(isVisibleFromSubclass(ProtectedClass.NestedPublicClass.class, samePackage)); + assertTrue(isVisibleFromSubclass(ProtectedClass.NestedProtectedClass.class, samePackage)); + assertTrue(isVisibleFromSubclass(ProtectedClass.NestedDefaultClass.class, samePackage)); + assertFalse(isVisibleFromSubclass(ProtectedClass.NestedPrivateClass.class, samePackage)); + + assertTrue(isVisibleFromSubclass(DefaultClass.NestedPublicClass.class, samePackage)); + assertTrue(isVisibleFromSubclass(DefaultClass.NestedProtectedClass.class, samePackage)); + assertTrue(isVisibleFromSubclass(DefaultClass.NestedDefaultClass.class, samePackage)); + assertFalse(isVisibleFromSubclass(DefaultClass.NestedPrivateClass.class, samePackage)); + + assertFalse(isVisibleFromSubclass(PrivateClass.NestedPublicClass.class, samePackage)); + assertFalse(isVisibleFromSubclass(PrivateClass.NestedProtectedClass.class, samePackage)); + assertFalse(isVisibleFromSubclass(PrivateClass.NestedDefaultClass.class, samePackage)); + assertFalse(isVisibleFromSubclass(PrivateClass.NestedPrivateClass.class, samePackage)); + + PackageElement otherPackage = compilation.getElements().getPackageElement("com.example"); + assertTrue(isVisibleFromSubclass(PublicClass.class, otherPackage)); + assertTrue(isVisibleFromSubclass(ProtectedClass.class, otherPackage)); + assertFalse(isVisibleFromSubclass(DefaultClass.class, otherPackage)); + assertFalse(isVisibleFromSubclass(PrivateClass.class, otherPackage)); + + assertTrue(isVisibleFromSubclass(PublicClass.NestedPublicClass.class, otherPackage)); + assertTrue(isVisibleFromSubclass(PublicClass.NestedProtectedClass.class, otherPackage)); + assertFalse(isVisibleFromSubclass(PublicClass.NestedDefaultClass.class, otherPackage)); + assertFalse(isVisibleFromSubclass(PublicClass.NestedPrivateClass.class, otherPackage)); + + assertTrue(isVisibleFromSubclass(ProtectedClass.NestedPublicClass.class, otherPackage)); + assertTrue(isVisibleFromSubclass(ProtectedClass.NestedProtectedClass.class, otherPackage)); + assertFalse(isVisibleFromSubclass(ProtectedClass.NestedDefaultClass.class, otherPackage)); + assertFalse(isVisibleFromSubclass(ProtectedClass.NestedPrivateClass.class, otherPackage)); + + assertFalse(isVisibleFromSubclass(DefaultClass.NestedPublicClass.class, otherPackage)); + assertFalse(isVisibleFromSubclass(DefaultClass.NestedProtectedClass.class, otherPackage)); + assertFalse(isVisibleFromSubclass(DefaultClass.NestedDefaultClass.class, otherPackage)); + assertFalse(isVisibleFromSubclass(DefaultClass.NestedPrivateClass.class, otherPackage)); + + assertFalse(isVisibleFromSubclass(PrivateClass.NestedPublicClass.class, otherPackage)); + assertFalse(isVisibleFromSubclass(PrivateClass.NestedProtectedClass.class, otherPackage)); + assertFalse(isVisibleFromSubclass(PrivateClass.NestedDefaultClass.class, otherPackage)); + assertFalse(isVisibleFromSubclass(PrivateClass.NestedPrivateClass.class, otherPackage)); + } + + private boolean isVisibleFromSubclass(Class clazz, PackageElement from) { + return Visibility.isVisibleFromSubclass( + compilation.getElements().getTypeElement(clazz.getCanonicalName()), from); + } }