dagger.internal.codegen.writing.StaticMemberSelects Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of dagger-compiler Show documentation
Show all versions of dagger-compiler Show documentation
A fast dependency injector for Android and Java.
The newest version!
/*
* 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.internal.codegen.writing;
import static com.google.common.base.Preconditions.checkArgument;
import static com.google.common.base.Preconditions.checkNotNull;
import static dagger.internal.codegen.binding.SourceFiles.bindingTypeElementTypeVariableNames;
import static dagger.internal.codegen.binding.SourceFiles.generatedClassNameForBinding;
import static dagger.internal.codegen.binding.SourceFiles.setFactoryClassName;
import static dagger.internal.codegen.javapoet.CodeBlocks.toParametersCodeBlock;
import static dagger.internal.codegen.javapoet.TypeNames.DAGGER_PROVIDER;
import static dagger.internal.codegen.javapoet.TypeNames.FACTORY;
import static dagger.internal.codegen.javapoet.TypeNames.MAP_FACTORY;
import static dagger.internal.codegen.javapoet.TypeNames.PRODUCER;
import static dagger.internal.codegen.javapoet.TypeNames.PRODUCERS;
import static dagger.internal.codegen.langmodel.Accessibility.isTypeAccessibleFrom;
import static dagger.internal.codegen.xprocessing.XTypes.isDeclared;
import androidx.room.compiler.processing.XType;
import com.google.common.collect.ImmutableList;
import com.squareup.javapoet.ClassName;
import com.squareup.javapoet.CodeBlock;
import com.squareup.javapoet.TypeVariableName;
import dagger.internal.codegen.base.SetType;
import dagger.internal.codegen.binding.Binding;
import dagger.internal.codegen.binding.BindingType;
import dagger.internal.codegen.binding.ContributionBinding;
import dagger.internal.codegen.javapoet.CodeBlocks;
/** Helper class for static member select creation. */
final class StaticMemberSelects {
/** A {@link MemberSelect} for a factory of an empty map. */
static MemberSelect emptyMapFactory(Binding binding) {
BindingType bindingType = binding.bindingType();
ImmutableList typeParameters =
ImmutableList.copyOf(binding.key().type().xprocessing().getTypeArguments());
return bindingType.equals(BindingType.PRODUCTION)
? new ParameterizedStaticMethod(
PRODUCERS, typeParameters, CodeBlock.of("emptyMapProducer()"), PRODUCER)
: new ParameterizedStaticMethod(
MAP_FACTORY, typeParameters, CodeBlock.of("emptyMapProvider()"), DAGGER_PROVIDER);
}
/**
* A static member select for an empty set factory. Calls {@link
* dagger.internal.SetFactory#empty()}, {@link dagger.producers.internal.SetProducer#empty()}, or
* {@link dagger.producers.internal.SetOfProducedProducer#empty()}, depending on the set bindings.
*/
static MemberSelect emptySetFactory(ContributionBinding binding) {
return new ParameterizedStaticMethod(
setFactoryClassName(binding),
ImmutableList.of(SetType.from(binding.key()).elementType()),
CodeBlock.of("empty()"),
FACTORY);
}
/**
* Returns a {@link MemberSelect} for the instance of a {@code create()} method on a factory with
* no arguments.
*/
static MemberSelect factoryCreateNoArgumentMethod(Binding binding) {
checkArgument(
binding.bindingType().equals(BindingType.PROVISION),
"Invalid binding type: %s",
binding.bindingType());
checkArgument(
binding.dependencies().isEmpty() && !binding.scope().isPresent(),
"%s should have no dependencies and be unscoped to create a no argument factory.",
binding);
ClassName factoryName = generatedClassNameForBinding(binding);
XType keyType = binding.key().type().xprocessing();
if (isDeclared(keyType)) {
ImmutableList typeVariables = bindingTypeElementTypeVariableNames(binding);
if (!typeVariables.isEmpty()) {
ImmutableList typeArguments = ImmutableList.copyOf(keyType.getTypeArguments());
return new ParameterizedStaticMethod(
factoryName, typeArguments, CodeBlock.of("create()"), FACTORY);
}
}
return new StaticMethod(factoryName, CodeBlock.of("create()"));
}
private static final class StaticMethod extends MemberSelect {
private final CodeBlock methodCodeBlock;
StaticMethod(ClassName owningClass, CodeBlock methodCodeBlock) {
super(owningClass, true);
this.methodCodeBlock = checkNotNull(methodCodeBlock);
}
@Override
CodeBlock getExpressionFor(ClassName usingClass) {
return owningClass().equals(usingClass)
? methodCodeBlock
: CodeBlock.of("$T.$L", owningClass(), methodCodeBlock);
}
}
private static final class ParameterizedStaticMethod extends MemberSelect {
private final ImmutableList typeParameters;
private final CodeBlock methodCodeBlock;
private final ClassName rawReturnType;
ParameterizedStaticMethod(
ClassName owningClass,
ImmutableList typeParameters,
CodeBlock methodCodeBlock,
ClassName rawReturnType) {
super(owningClass, true);
this.typeParameters = typeParameters;
this.methodCodeBlock = methodCodeBlock;
this.rawReturnType = rawReturnType;
}
@Override
CodeBlock getExpressionFor(ClassName usingClass) {
boolean isAccessible =
typeParameters.stream().allMatch(t -> isTypeAccessibleFrom(t, usingClass.packageName()));
if (isAccessible) {
return CodeBlock.of(
"$T.<$L>$L",
owningClass(),
typeParameters.stream().map(CodeBlocks::type).collect(toParametersCodeBlock()),
methodCodeBlock);
} else {
return CodeBlock.of("(($T) $T.$L)", rawReturnType, owningClass(), methodCodeBlock);
}
}
}
private StaticMemberSelects() {}
}