All Downloads are FREE. Search and download functionalities are using the official Maven repository.

dagger.internal.codegen.langmodel.Accessibility Maven / Gradle / Ivy

There is a newer version: 2.45-kim-rc1
Show newest version
/*
 * Copyright (C) 2015 The Dagger Authors.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package dagger.internal.codegen.langmodel;

import static androidx.room.compiler.processing.compat.XConverters.toJavac;
import static com.google.auto.common.MoreElements.getPackage;
import static com.google.auto.common.MoreTypes.asElement;
import static com.google.common.base.Preconditions.checkArgument;
import static javax.lang.model.element.Modifier.PRIVATE;
import static javax.lang.model.element.Modifier.PUBLIC;

import androidx.room.compiler.processing.XElement;
import java.util.Optional;
import javax.lang.model.element.Element;
import javax.lang.model.element.ElementKind;
import javax.lang.model.element.ExecutableElement;
import javax.lang.model.element.PackageElement;
import javax.lang.model.element.TypeElement;
import javax.lang.model.element.TypeParameterElement;
import javax.lang.model.element.VariableElement;
import javax.lang.model.type.ArrayType;
import javax.lang.model.type.DeclaredType;
import javax.lang.model.type.NoType;
import javax.lang.model.type.NullType;
import javax.lang.model.type.PrimitiveType;
import javax.lang.model.type.TypeKind;
import javax.lang.model.type.TypeMirror;
import javax.lang.model.type.TypeVariable;
import javax.lang.model.type.WildcardType;
import javax.lang.model.util.SimpleElementVisitor8;
import javax.lang.model.util.SimpleTypeVisitor8;

/**
 * Utility methods for determining whether a {@linkplain TypeMirror type} or an {@linkplain Element
 * element} is accessible given the rules outlined in section 6.6 of the
 * Java Language Specification.
 *
 * 

This class only provides an approximation for accessibility. It does not always yield the same * result as the compiler, but will always err on the side of declaring something inaccessible. This * ensures that using this class will never result in generating code that will not compile. * *

Whenever compiler independence is not a requirement, the compiler-specific implementation of * this functionality should be preferred. For example, {@link * com.sun.source.util.Trees#isAccessible(com.sun.source.tree.Scope, TypeElement)} would be * preferable for {@code javac}. */ public final class Accessibility { /** Returns true if the given type can be referenced from any package. */ public static boolean isTypePubliclyAccessible(TypeMirror type) { return type.accept(new TypeAccessibilityVisitor(Optional.empty()), null); } /** Returns true if the given type can be referenced from code in the given package. */ public static boolean isTypeAccessibleFrom(TypeMirror type, String packageName) { return type.accept(new TypeAccessibilityVisitor(Optional.of(packageName)), null); } private static final class TypeAccessibilityVisitor extends SimpleTypeVisitor8 { private final Optional packageName; TypeAccessibilityVisitor(Optional packageName) { this.packageName = packageName; } boolean isAccessible(TypeMirror type) { return type.accept(this, null); } @Override public Boolean visitNoType(NoType type, Void p) { return true; } @Override public Boolean visitDeclared(DeclaredType type, Void p) { if (!isAccessible(type.getEnclosingType())) { // TODO(gak): investigate this check. see comment in Binding return false; } if (!type.asElement().accept(new ElementAccessibilityVisitor(packageName), null)) { return false; } for (TypeMirror typeArgument : type.getTypeArguments()) { if (!isAccessible(typeArgument)) { return false; } } return true; } @Override public Boolean visitArray(ArrayType type, Void p) { return type.getComponentType().accept(this, null); } @Override public Boolean visitPrimitive(PrimitiveType type, Void p) { return true; } @Override public Boolean visitNull(NullType type, Void p) { return true; } @Override public Boolean visitTypeVariable(TypeVariable type, Void p) { // a _reference_ to a type variable is always accessible return true; } @Override public Boolean visitWildcard(WildcardType type, Void p) { if (type.getExtendsBound() != null && !isAccessible(type.getExtendsBound())) { return false; } if (type.getSuperBound() != null && !isAccessible(type.getSuperBound())) { return false; } return true; } @Override protected Boolean defaultAction(TypeMirror type, Void p) { throw new IllegalArgumentException( String.format( "%s of kind %s should not be checked for accessibility", type, type.getKind())); } } /** Returns true if the given element can be referenced from any package. */ public static boolean isElementPubliclyAccessible(Element element) { return element.accept(new ElementAccessibilityVisitor(Optional.empty()), null); } /** Returns true if the given element can be referenced from code in the given package. */ // TODO(gak): account for protected // TODO(bcorso): account for kotlin srcs (package-private doesn't exist, internal does exist). public static boolean isElementAccessibleFrom(XElement element, String packageName) { return isElementAccessibleFrom(toJavac(element), packageName); } /** Returns true if the given element can be referenced from code in the given package. */ // TODO(gak): account for protected public static boolean isElementAccessibleFrom(Element element, String packageName) { return element.accept(new ElementAccessibilityVisitor(Optional.of(packageName)), null); } /** Returns true if the given element can be referenced from other code in its own package. */ public static boolean isElementAccessibleFromOwnPackage(Element element) { return isElementAccessibleFrom(element, getPackage(element).getQualifiedName().toString()); } private static final class ElementAccessibilityVisitor extends SimpleElementVisitor8 { private final Optional packageName; ElementAccessibilityVisitor(Optional packageName) { this.packageName = packageName; } @Override public Boolean visitPackage(PackageElement element, Void p) { return true; } @Override public Boolean visitType(TypeElement element, Void p) { switch (element.getNestingKind()) { case MEMBER: return accessibleMember(element); case TOP_LEVEL: return accessibleModifiers(element); case ANONYMOUS: case LOCAL: return false; } throw new AssertionError(); } boolean accessibleMember(Element element) { return element.getEnclosingElement().accept(this, null) && accessibleModifiers(element); } boolean accessibleModifiers(Element element) { if (element.getModifiers().contains(PUBLIC)) { return true; } else if (element.getModifiers().contains(PRIVATE)) { return false; } return packageName.isPresent() && getPackage(element).getQualifiedName().contentEquals(packageName.get()); } @Override public Boolean visitTypeParameter(TypeParameterElement element, Void p) { throw new IllegalArgumentException( "It does not make sense to check the accessibility of a type parameter"); } @Override public Boolean visitExecutable(ExecutableElement element, Void p) { return accessibleMember(element); } @Override public Boolean visitVariable(VariableElement element, Void p) { ElementKind kind = element.getKind(); checkArgument(kind.isField(), "checking a variable that isn't a field: %s", kind); return accessibleMember(element); } } /** Returns true if the raw type of {@code type} is accessible from the given package. */ public static boolean isRawTypeAccessible(TypeMirror type, String requestingPackage) { return type.getKind() == TypeKind.DECLARED ? isElementAccessibleFrom(asElement(type), requestingPackage) : isTypeAccessibleFrom(type, requestingPackage); } /** Returns true if the raw type of {@code type} is accessible from any package. */ public static boolean isRawTypePubliclyAccessible(TypeMirror type) { return type.getKind() == TypeKind.DECLARED ? isElementPubliclyAccessible(asElement(type)) : isTypePubliclyAccessible(type); } private Accessibility() {} }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy