diff --git a/java/dagger/internal/codegen/base/Scopes.java b/java/dagger/internal/codegen/base/Scopes.java index 591cf0974ad..203e793acd9 100644 --- a/java/dagger/internal/codegen/base/Scopes.java +++ b/java/dagger/internal/codegen/base/Scopes.java @@ -16,16 +16,18 @@ package dagger.internal.codegen.base; -import static com.google.common.collect.Iterables.getOnlyElement; import static dagger.internal.codegen.base.DiagnosticFormatting.stripCommonTypePrefixes; +import static dagger.internal.codegen.extension.DaggerCollectors.toOptional; import static dagger.internal.codegen.extension.DaggerStreams.toImmutableSet; import com.google.auto.common.AnnotationMirrors; import com.google.common.collect.ImmutableSet; +import com.squareup.javapoet.ClassName; +import dagger.internal.codegen.javapoet.TypeNames; import dagger.internal.codegen.langmodel.DaggerElements; import dagger.producers.ProductionScope; +import dagger.spi.model.DaggerAnnotation; import dagger.spi.model.Scope; -import java.lang.annotation.Annotation; import java.util.Optional; import javax.inject.Singleton; import javax.lang.model.element.Element; @@ -35,20 +37,22 @@ public final class Scopes { /** Returns a representation for {@link ProductionScope @ProductionScope} scope. */ public static Scope productionScope(DaggerElements elements) { - return scope(elements, ProductionScope.class); + return scope(elements, TypeNames.PRODUCTION_SCOPE); } /** Returns a representation for {@link Singleton @Singleton} scope. */ public static Scope singletonScope(DaggerElements elements) { - return scope(elements, Singleton.class); + return scope(elements, TypeNames.SINGLETON); } /** * Creates a {@link Scope} object from the {@link javax.inject.Scope}-annotated annotation type. */ - private static Scope scope( - DaggerElements elements, Class scopeAnnotationClass) { - return Scope.scope(SimpleAnnotationMirror.of(elements.getTypeElement(scopeAnnotationClass))); + private static Scope scope(DaggerElements elements, ClassName scopeAnnotationClassName) { + return Scope.scope( + DaggerAnnotation.fromJava( + SimpleAnnotationMirror.of( + elements.getTypeElement(scopeAnnotationClassName.canonicalName())))); } /** @@ -56,8 +60,7 @@ private static Scope scope( * exception if there are more than one. */ public static Optional uniqueScopeOf(Element element) { - // TODO(ronshapiro): Use MoreCollectors.toOptional() once we can use guava-jre - return Optional.ofNullable(getOnlyElement(scopesOf(element), null)); + return scopesOf(element).stream().collect(toOptional()); } /** @@ -72,8 +75,10 @@ public static String getReadableSource(Scope scope) { /** Returns all of the associated scopes for a source code element. */ public static ImmutableSet scopesOf(Element element) { + // TODO(bcorso): Replace Scope class reference with class name once auto-common is updated. return AnnotationMirrors.getAnnotatedAnnotations(element, javax.inject.Scope.class) .stream() + .map(DaggerAnnotation::fromJava) .map(Scope::scope) .collect(toImmutableSet()); } diff --git a/java/dagger/internal/codegen/javapoet/TypeNames.java b/java/dagger/internal/codegen/javapoet/TypeNames.java index e9475fae747..14fa339c30f 100644 --- a/java/dagger/internal/codegen/javapoet/TypeNames.java +++ b/java/dagger/internal/codegen/javapoet/TypeNames.java @@ -112,8 +112,12 @@ public final class TypeNames { ClassName.get("dagger.producers.internal", "SetOfProducedProducer"); public static final ClassName SET_PRODUCER = ClassName.get("dagger.producers.internal", "SetProducer"); + public static final ClassName PRODUCTION_SCOPE = + ClassName.get("dagger.producers", "ProductionScope"); // Other classnames + public static final ClassName SINGLETON = ClassName.get("javax.inject", "Singleton"); + public static final ClassName SCOPE = ClassName.get("javax.inject", "Scope"); public static final ClassName INJECT = ClassName.get("javax.inject", "Inject"); public static final ClassName LIST = ClassName.get("java.util", "List"); public static final ClassName SET = ClassName.get("java.util", "Set"); diff --git a/java/dagger/internal/codegen/validation/BindingElementValidator.java b/java/dagger/internal/codegen/validation/BindingElementValidator.java index ea8f819d882..dd2de3fd1ec 100644 --- a/java/dagger/internal/codegen/validation/BindingElementValidator.java +++ b/java/dagger/internal/codegen/validation/BindingElementValidator.java @@ -369,7 +369,7 @@ private void checkScopes() { } verifyNotNull(error); for (Scope scope : scopes) { - report.addError(error, element, scope.scopeAnnotation()); + report.addError(error, element, scope.scopeAnnotation().java()); } } diff --git a/java/dagger/internal/codegen/validation/ExternalBindingGraphConverter.java b/java/dagger/internal/codegen/validation/ExternalBindingGraphConverter.java index 84b3f56cabe..e6e14e445ba 100644 --- a/java/dagger/internal/codegen/validation/ExternalBindingGraphConverter.java +++ b/java/dagger/internal/codegen/validation/ExternalBindingGraphConverter.java @@ -151,7 +151,7 @@ private static DependencyRequest fromSpiModel(dagger.spi.model.DependencyRequest } private static Scope fromSpiModel(dagger.spi.model.Scope scope) { - return Scope.scope(scope.scopeAnnotation()); + return Scope.scope(scope.scopeAnnotation().java()); } private static ComponentPath fromSpiModel(dagger.spi.model.ComponentPath path) { diff --git a/java/dagger/internal/codegen/validation/InjectValidator.java b/java/dagger/internal/codegen/validation/InjectValidator.java index 39910ba5c00..4db9c10a507 100644 --- a/java/dagger/internal/codegen/validation/InjectValidator.java +++ b/java/dagger/internal/codegen/validation/InjectValidator.java @@ -172,7 +172,7 @@ && isAnnotationPresent(constructorElement, AssistedInject.class)) { } for (Scope scope : scopesOf(constructorElement)) { - builder.addError(scopeErrorMsg, constructorElement, scope.scopeAnnotation()); + builder.addError(scopeErrorMsg, constructorElement, scope.scopeAnnotation().java()); } for (VariableElement parameter : constructorElement.getParameters()) { @@ -229,14 +229,14 @@ && isAnnotationPresent(constructorElement, AssistedInject.class)) { builder.addError( "A type with an @AssistedInject-annotated constructor cannot be scoped", enclosingElement, - scope.scopeAnnotation()); + scope.scopeAnnotation().java()); } } else if (scopes.size() > 1) { for (Scope scope : scopes) { builder.addError( "A single binding may not declare more than one @Scope", enclosingElement, - scope.scopeAnnotation()); + scope.scopeAnnotation().java()); } } diff --git a/java/dagger/spi/model/DaggerAnnotation.java b/java/dagger/spi/model/DaggerAnnotation.java index 3451a6aff14..9648f21f783 100644 --- a/java/dagger/spi/model/DaggerAnnotation.java +++ b/java/dagger/spi/model/DaggerAnnotation.java @@ -17,10 +17,12 @@ package dagger.spi.model; import com.google.auto.common.AnnotationMirrors; +import com.google.auto.common.MoreTypes; import com.google.auto.value.AutoValue; import com.google.common.base.Equivalence; import com.google.common.base.Preconditions; import com.google.devtools.ksp.symbol.KSAnnotation; +import com.squareup.javapoet.ClassName; import javax.annotation.Nullable; import javax.lang.model.element.AnnotationMirror; @@ -43,6 +45,15 @@ public static DaggerAnnotation fromKsp(KSAnnotation ksAnnotation) { @Nullable abstract Equivalence.Wrapper annotationMirror(); + public DaggerTypeElement annotationTypeElement() { + return DaggerTypeElement.fromJava( + MoreTypes.asTypeElement(annotationMirror().get().getAnnotationType())); + } + + public ClassName className() { + return annotationTypeElement().className(); + } + @Nullable public AnnotationMirror java() { return annotationMirror().get(); @@ -53,6 +64,6 @@ public AnnotationMirror java() { @Override public final String toString() { - return java().toString(); + return (ksp() != null ? ksp() : java()).toString(); } } diff --git a/java/dagger/spi/model/DaggerElement.java b/java/dagger/spi/model/DaggerElement.java new file mode 100644 index 00000000000..730fbdb2d77 --- /dev/null +++ b/java/dagger/spi/model/DaggerElement.java @@ -0,0 +1,43 @@ +/* + * Copyright (C) 2021 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.spi.model; + +import com.google.auto.value.AutoValue; +import com.google.common.base.Preconditions; +import com.google.devtools.ksp.symbol.KSDeclaration; +import javax.annotation.Nullable; +import javax.lang.model.element.Element; + +/** Wrapper type for an element. */ +@AutoValue +public abstract class DaggerElement { + + public static DaggerElement fromJava(Element element) { + return new AutoValue_DaggerElement(Preconditions.checkNotNull(element), null); + } + + @Nullable + public abstract Element java(); + + @Nullable + public abstract KSDeclaration ksp(); + + @Override + public final String toString() { + return (ksp() != null ? ksp() : java()).toString(); + } +} diff --git a/java/dagger/spi/model/DaggerExecutableElement.java b/java/dagger/spi/model/DaggerExecutableElement.java new file mode 100644 index 00000000000..15379dcc536 --- /dev/null +++ b/java/dagger/spi/model/DaggerExecutableElement.java @@ -0,0 +1,43 @@ +/* + * Copyright (C) 2021 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.spi.model; + +import com.google.auto.value.AutoValue; +import com.google.common.base.Preconditions; +import com.google.devtools.ksp.symbol.KSFunctionDeclaration; +import javax.annotation.Nullable; +import javax.lang.model.element.ExecutableElement; + +/** Wrapper type for an executable element. */ +@AutoValue +public abstract class DaggerExecutableElement { + + public static DaggerExecutableElement fromJava(ExecutableElement element) { + return new AutoValue_DaggerExecutableElement(Preconditions.checkNotNull(element), null); + } + + @Nullable + public abstract ExecutableElement java(); + + @Nullable + public abstract KSFunctionDeclaration ksp(); + + @Override + public final String toString() { + return (ksp() != null ? ksp() : java()).toString(); + } +} diff --git a/java/dagger/spi/model/DaggerType.java b/java/dagger/spi/model/DaggerType.java index db1e03ca192..3cb22068a44 100644 --- a/java/dagger/spi/model/DaggerType.java +++ b/java/dagger/spi/model/DaggerType.java @@ -53,6 +53,6 @@ public TypeMirror java() { @Override public final String toString() { - return java().toString(); + return (ksp() != null ? ksp() : java()).toString(); } } diff --git a/java/dagger/spi/model/DaggerTypeElement.java b/java/dagger/spi/model/DaggerTypeElement.java new file mode 100644 index 00000000000..8be1ae0f6a6 --- /dev/null +++ b/java/dagger/spi/model/DaggerTypeElement.java @@ -0,0 +1,54 @@ +/* + * Copyright (C) 2021 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.spi.model; + +import com.google.auto.value.AutoValue; +import com.google.common.base.Preconditions; +import com.google.devtools.ksp.symbol.KSClassDeclaration; +import com.squareup.javapoet.ClassName; +import javax.annotation.Nullable; +import javax.lang.model.element.TypeElement; + +/** Wrapper type for a type element. */ +@AutoValue +public abstract class DaggerTypeElement { + + public static DaggerTypeElement fromJava(TypeElement element) { + return new AutoValue_DaggerTypeElement(Preconditions.checkNotNull(element), null); + } + + @Nullable + public abstract TypeElement java(); + + @Nullable + public abstract KSClassDeclaration ksp(); + + public ClassName className() { + if (ksp() != null) { + // TODO(bcorso): Add support for KSP. Consider using xprocessing types internally since that + // already has support for KSP class names? + throw new UnsupportedOperationException("Method className() is not yet supported in KSP."); + } else { + return ClassName.get(java()); + } + } + + @Override + public final String toString() { + return (ksp() != null ? ksp() : java()).toString(); + } +} diff --git a/java/dagger/spi/model/Scope.java b/java/dagger/spi/model/Scope.java index 980e1c88347..08def0b85b5 100644 --- a/java/dagger/spi/model/Scope.java +++ b/java/dagger/spi/model/Scope.java @@ -19,73 +19,69 @@ import static com.google.auto.common.MoreElements.isAnnotationPresent; import static com.google.common.base.Preconditions.checkArgument; -import com.google.auto.common.AnnotationMirrors; -import com.google.auto.common.MoreElements; -import com.google.auto.common.MoreTypes; import com.google.auto.value.AutoValue; -import com.google.common.base.Equivalence; -import dagger.Reusable; -import dagger.producers.ProductionScope; -import java.lang.annotation.Annotation; -import javax.inject.Singleton; -import javax.lang.model.element.AnnotationMirror; -import javax.lang.model.element.TypeElement; +import com.squareup.javapoet.ClassName; /** A representation of a {@link javax.inject.Scope}. */ @AutoValue -// TODO(ronshapiro): point to SimpleAnnotationMirror public abstract class Scope { - abstract Equivalence.Wrapper wrappedScopeAnnotation(); - - /** The {@link AnnotationMirror} that represents the scope annotation. */ - public final AnnotationMirror scopeAnnotation() { - return wrappedScopeAnnotation().get(); - } - - /** The scope annotation element. */ - public final TypeElement scopeAnnotationElement() { - return MoreTypes.asTypeElement(scopeAnnotation().getAnnotationType()); - } - /** * Creates a {@link Scope} object from the {@link javax.inject.Scope}-annotated annotation type. */ - public static Scope scope(AnnotationMirror scopeAnnotation) { + public static Scope scope(DaggerAnnotation scopeAnnotation) { checkArgument(isScope(scopeAnnotation)); - return new AutoValue_Scope(AnnotationMirrors.equivalence().wrap(scopeAnnotation)); + return new AutoValue_Scope(scopeAnnotation); } /** * Returns {@code true} if {@link #scopeAnnotation()} is a {@link javax.inject.Scope} annotation. */ - public static boolean isScope(AnnotationMirror scopeAnnotation) { - return isScope(MoreElements.asType(scopeAnnotation.getAnnotationType().asElement())); + public static boolean isScope(DaggerAnnotation scopeAnnotation) { + return isScope(scopeAnnotation.annotationTypeElement()); } /** * Returns {@code true} if {@code scopeAnnotationType} is a {@link javax.inject.Scope} annotation. */ - public static boolean isScope(TypeElement scopeAnnotationType) { - return isAnnotationPresent(scopeAnnotationType, javax.inject.Scope.class); + public static boolean isScope(DaggerTypeElement scopeAnnotationType) { + // TODO(bcorso): Replace Scope class reference with class name once auto-common is updated. + return isAnnotationPresent(scopeAnnotationType.java(), javax.inject.Scope.class); + } + + private static final ClassName PRODUCTION_SCOPE = + ClassName.get("dagger.producers", "ProductionScope"); + private static final ClassName SINGLETON = ClassName.get("javax.inject", "Singleton"); + private static final ClassName REUSABLE = ClassName.get("dagger", "Reusable"); + private static final ClassName SCOPE = ClassName.get("javax.inject", "Scope"); + + + /** The {@link DaggerAnnotation} that represents the scope annotation. */ + public abstract DaggerAnnotation scopeAnnotation(); + + public final ClassName className() { + return scopeAnnotation().className(); } - /** Returns {@code true} if this scope is the {@link Singleton @Singleton} scope. */ + /** Returns {@code true} if this scope is the {@link javax.inject.Singleton @Singleton} scope. */ public final boolean isSingleton() { - return isScope(Singleton.class); + return isScope(SINGLETON); } - /** Returns {@code true} if this scope is the {@link Reusable @Reusable} scope. */ + /** Returns {@code true} if this scope is the {@link dagger.Reusable @Reusable} scope. */ public final boolean isReusable() { - return isScope(Reusable.class); + return isScope(REUSABLE); } - /** Returns {@code true} if this scope is the {@link ProductionScope @ProductionScope} scope. */ + /** + * Returns {@code true} if this scope is the {@link + * dagger.producers.ProductionScope @ProductionScope} scope. + */ public final boolean isProductionScope() { - return isScope(ProductionScope.class); + return isScope(PRODUCTION_SCOPE); } - private boolean isScope(Class annotation) { - return scopeAnnotationElement().getQualifiedName().contentEquals(annotation.getCanonicalName()); + private boolean isScope(ClassName annotation) { + return scopeAnnotation().className().equals(annotation); } /** Returns a debug representation of the scope. */