dagger.internal.codegen.langmodel.Accessibility Maven / Gradle / Ivy
Show all versions of dagger-compiler Show documentation
/*
* 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.XElementKt.isField;
import static androidx.room.compiler.processing.XElementKt.isTypeElement;
import static androidx.room.compiler.processing.XTypeKt.isArray;
import static dagger.internal.codegen.xprocessing.XElements.asTypeElement;
import static dagger.internal.codegen.xprocessing.XElements.isExecutable;
import static dagger.internal.codegen.xprocessing.XElements.isPackage;
import static dagger.internal.codegen.xprocessing.XElements.isPrivate;
import static dagger.internal.codegen.xprocessing.XElements.isPublic;
import static dagger.internal.codegen.xprocessing.XTypeElements.isNested;
import static dagger.internal.codegen.xprocessing.XTypes.asArray;
import static dagger.internal.codegen.xprocessing.XTypes.getEnclosingType;
import static dagger.internal.codegen.xprocessing.XTypes.isDeclared;
import static dagger.internal.codegen.xprocessing.XTypes.isNoType;
import static dagger.internal.codegen.xprocessing.XTypes.isNullType;
import static dagger.internal.codegen.xprocessing.XTypes.isPrimitive;
import static dagger.internal.codegen.xprocessing.XTypes.isTypeVariable;
import static dagger.internal.codegen.xprocessing.XTypes.isWildcard;
import androidx.room.compiler.processing.XElement;
import androidx.room.compiler.processing.XProcessingEnv;
import androidx.room.compiler.processing.XType;
import com.squareup.javapoet.ClassName;
import com.squareup.javapoet.TypeName;
import java.util.Optional;
/**
* Utility methods for determining whether a {@link XType} or an {@link XElement} 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.
*/
public final class Accessibility {
/** Returns true if the given type can be referenced from any package. */
public static boolean isTypePubliclyAccessible(XType type) {
return isTypeAccessibleFrom(type, Optional.empty());
}
/** Returns true if the given type can be referenced from code in the given package. */
public static boolean isTypeAccessibleFrom(XType type, String packageName) {
return isTypeAccessibleFrom(type, Optional.of(packageName));
}
private static boolean isTypeAccessibleFrom(XType type, Optional packageName) {
if (isNoType(type) || isPrimitive(type) || isNullType(type) || isTypeVariable(type)) {
return true;
} else if (isArray(type)) {
return isTypeAccessibleFrom(asArray(type).getComponentType(), packageName);
} else if (isDeclared(type)) {
XType enclosingType = getEnclosingType(type);
if (enclosingType != null && !isTypeAccessibleFrom(enclosingType, packageName)) {
return false;
}
if (!isElementAccessibleFrom(type.getTypeElement(), packageName)) {
return false;
}
return type.getTypeArguments().stream()
.allMatch(typeArgument -> isTypeAccessibleFrom(typeArgument, packageName));
} else if (isWildcard(type)) {
return type.extendsBound() == null || isTypeAccessibleFrom(type.extendsBound(), packageName);
}
throw new AssertionError(String.format("%s should not be checked for accessibility", type));
}
/** Returns true if the given element can be referenced from any package. */
public static boolean isElementPubliclyAccessible(XElement element) {
return isElementAccessibleFrom(element, Optional.empty());
}
/** Returns true if the given element can be referenced from other code in its own package. */
public static boolean isElementAccessibleFromOwnPackage(XElement element) {
return isElementAccessibleFrom(
element, Optional.of(element.getClosestMemberContainer().getClassName().packageName()));
}
/** 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(element, Optional.of(packageName));
}
private static boolean isElementAccessibleFrom(XElement element, Optional packageName) {
if (isPackage(element)) {
return true;
} else if (isTypeElement(element)) {
return isNested(asTypeElement(element))
? accessibleMember(element, packageName)
: accessibleModifiers(element, packageName);
} else if (isExecutable(element) || isField(element)) {
return accessibleMember(element, packageName);
}
throw new AssertionError();
}
private static boolean accessibleMember(XElement element, Optional packageName) {
return isElementAccessibleFrom(element.getEnclosingElement(), packageName)
&& accessibleModifiers(element, packageName);
}
private static boolean accessibleModifiers(XElement element, Optional packageName) {
if (isPublic(element)) {
return true;
} else if (isPrivate(element)) {
return false;
}
return packageName.isPresent()
&& element
.getClosestMemberContainer()
.getClassName()
.packageName()
.contentEquals(packageName.get());
}
/** Returns true if the raw type of {@code type} is accessible from the given package. */
public static boolean isRawTypeAccessible(XType type, String requestingPackage) {
return isDeclared(type)
? isElementAccessibleFrom(type.getTypeElement(), requestingPackage)
: isTypeAccessibleFrom(type, requestingPackage);
}
/** Returns true if the raw type of {@code type} is accessible from any package. */
public static boolean isRawTypePubliclyAccessible(XType type) {
return isDeclared(type)
? isElementPubliclyAccessible(type.getTypeElement())
: isTypePubliclyAccessible(type);
}
/**
* Returns an accessible type in {@code requestingClass}'s package based on {@code type}:
*
*
* - If {@code type} is accessible from the package, returns it.
*
- If not, but {@code type}'s raw type is accessible from the package, returns the raw type.
*
- Otherwise returns {@link Object}.
*
*/
public static TypeName accessibleTypeName(
XType type, ClassName requestingClass, XProcessingEnv processingEnv) {
if (isTypeAccessibleFrom(type, requestingClass.packageName())) {
return type.getTypeName();
} else if (isDeclared(type) && isRawTypeAccessible(type, requestingClass.packageName())) {
return type.getRawType().getTypeName();
} else {
return TypeName.OBJECT;
}
}
private Accessibility() {}
}