dagger.internal.codegen.xprocessing.XProcessingEnvs Maven / Gradle / Ivy
Show all versions of dagger-compiler Show documentation
/*
* Copyright (C) 2022 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.xprocessing;
import static androidx.room.compiler.processing.compat.XConverters.getProcessingEnv;
import static androidx.room.compiler.processing.compat.XConverters.toJavac;
import static androidx.room.compiler.processing.compat.XConverters.toXProcessing;
import static com.google.common.base.Preconditions.checkArgument;
import static com.google.common.collect.Iterables.getOnlyElement;
import androidx.room.compiler.processing.XMethodElement;
import androidx.room.compiler.processing.XProcessingEnv;
import androidx.room.compiler.processing.XType;
import androidx.room.compiler.processing.XTypeElement;
import androidx.room.compiler.processing.compat.XConverters;
import com.squareup.javapoet.ClassName;
import com.squareup.javapoet.TypeName;
import java.util.Optional;
import javax.lang.model.SourceVersion;
import javax.lang.model.type.TypeKind;
/** A utility class for {@link XProcessingEnvs} helper methods. */
// TODO(bcorso): Consider moving these methods into XProcessing library.
public final class XProcessingEnvs {
/** Returns {@code true} if the sources are being compiled on a javac and the version is <= 8. */
public static boolean isPreJava8SourceVersion(XProcessingEnv processingEnv) {
Optional javaSourceVersion = javaSourceVersion(processingEnv);
return javaSourceVersion.isPresent()
&& javaSourceVersion.get().compareTo(SourceVersion.RELEASE_8) < 0;
}
/**
* Returns an optional containing the java source version if the current sources are being
* compiled with javac, or else returns an empty optional.
*/
private static Optional javaSourceVersion(XProcessingEnv processingEnv) {
switch (processingEnv.getBackend()) {
case JAVAC:
return Optional.of(toJavac(processingEnv).getSourceVersion());
case KSP:
return Optional.empty();
}
throw new AssertionError("Unexpected backend: " + processingEnv.getBackend());
}
/**
* Returns {@code true} if {@code overrider} overrides {@code overridden} from within {@code type}
*/
public static boolean javacOverrides(
XMethodElement overrider,
XMethodElement overridden,
XTypeElement type) {
XProcessingEnv processingEnv = getProcessingEnv(type);
switch (processingEnv.getBackend()) {
case JAVAC:
// TODO(bcorso): Investigate why XMethodElement#overrides() throws exception in some cases.
return toJavac(processingEnv)
.getElementUtils() // ALLOW_TYPES_ELEMENTS
.overrides(toJavac(overrider), toJavac(overridden), toJavac(type));
case KSP:
// For KSP, just use the standard overrides since the issues above are specific to javac.
return overrider.overrides(overridden, type);
}
throw new AssertionError("Unexpected backend: " + processingEnv.getBackend());
}
/** Returns a new unbounded wildcard type argument, i.e. {@code >}. */
public static XType getUnboundedWildcardType(XProcessingEnv processingEnv) {
switch (processingEnv.getBackend()) {
case JAVAC:
return toXProcessing(
toJavac(processingEnv)
.getTypeUtils() // ALLOW_TYPES_ELEMENTS
.getWildcardType(null, null),
processingEnv);
case KSP:
// In KSP, the equivalent of an unbounded wildcard type is the star projection. However,
// there's currently no way to create a star projection type directly. Instead, we create a
// List type, get its star projection, and then grab the type argument from that.
return XConverters.toXProcessing(
XConverters.toKS(processingEnv.requireType("java.util.List")).starProjection(),
processingEnv)
.getTypeArguments()
.get(0);
}
throw new AssertionError("Unexpected backend: " + processingEnv.getBackend());
}
/**
* Returns {@code type}'s single type argument.
*
* For example, if {@code type} is {@code List} this will return {@code Number}.
*
* @throws IllegalArgumentException if {@code type} is not a declared type or has zero or more
* than one type arguments.
*/
public static XType unwrapType(XType type) {
XType unwrapped = unwrapTypeOrDefault(type, null);
checkArgument(unwrapped != null, "%s is a raw type", type);
return unwrapped;
}
/**
* Returns {@code type}'s single type argument, if one exists, or {@link Object} if not.
*
* For example, if {@code type} is {@code List} this will return {@code Number}.
*
* @throws IllegalArgumentException if {@code type} is not a declared type or has more than one
* type argument.
*/
public static XType unwrapTypeOrObject(XType type, XProcessingEnv processingEnv) {
return unwrapTypeOrDefault(type, processingEnv.requireType(TypeName.OBJECT));
}
private static XType unwrapTypeOrDefault(XType type, XType defaultType) {
XTypeElement typeElement = type.getTypeElement();
checkArgument(
!typeElement.getType().getTypeArguments().isEmpty(),
"%s does not have a type parameter",
typeElement.getQualifiedName());
return getOnlyElement(type.getTypeArguments(), defaultType);
}
/** Returns a primitive int {@link XType}. */
public static XType getPrimitiveIntType(XProcessingEnv processingEnv) {
return toXProcessing(
toJavac(processingEnv)
.getTypeUtils() // ALLOW_TYPES_ELEMENTS
.getPrimitiveType(TypeKind.INT),
processingEnv);
}
/** Returns the type this method is enclosed in. */
public static XType wrapType(ClassName wrapper, XType type, XProcessingEnv processingEnv) {
return processingEnv.getDeclaredType(processingEnv.requireTypeElement(wrapper), type);
}
private XProcessingEnvs() {}
}