/* * Copyright (C) 2014 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.binding; import static androidx.room.compiler.codegen.XTypeNameKt.toJavaPoet; import static androidx.room.compiler.processing.XElementKt.isConstructor; import static com.google.common.base.CaseFormat.LOWER_CAMEL; import static com.google.common.base.CaseFormat.UPPER_CAMEL; import static com.google.common.base.Preconditions.checkArgument; import static com.google.common.base.Verify.verify; import static dagger.internal.codegen.javapoet.TypeNames.DOUBLE_CHECK; import static dagger.internal.codegen.javapoet.TypeNames.PRODUCER; import static dagger.internal.codegen.javapoet.TypeNames.PROVIDER; import static dagger.internal.codegen.javapoet.TypeNames.PROVIDER_OF_LAZY; import static dagger.internal.codegen.model.BindingKind.ASSISTED_INJECTION; import static dagger.internal.codegen.model.BindingKind.INJECTION; import static dagger.internal.codegen.xprocessing.XElements.asExecutable; import static dagger.internal.codegen.xprocessing.XElements.asMethod; import static dagger.internal.codegen.xprocessing.XElements.asTypeElement; import static dagger.internal.codegen.xprocessing.XElements.getSimpleName; import static dagger.internal.codegen.xprocessing.XTypeElements.typeVariableNames; import static dagger.internal.codegen.xprocessing.XTypeNames.simpleName; import static javax.lang.model.SourceVersion.isName; import androidx.room.compiler.codegen.XClassName; import androidx.room.compiler.processing.XExecutableElement; import androidx.room.compiler.processing.XFieldElement; import androidx.room.compiler.processing.XMethodElement; import androidx.room.compiler.processing.XTypeElement; import com.google.common.base.Joiner; import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableMap; import com.google.common.collect.ImmutableSet; import com.google.common.collect.Iterables; import com.google.common.collect.Maps; import com.squareup.javapoet.ClassName; import com.squareup.javapoet.CodeBlock; import com.squareup.javapoet.FieldSpec; import com.squareup.javapoet.ParameterizedTypeName; import com.squareup.javapoet.TypeName; import com.squareup.javapoet.TypeVariableName; import dagger.internal.codegen.base.MapType; import dagger.internal.codegen.base.SetType; import dagger.internal.codegen.binding.MembersInjectionBinding.InjectionSite; import dagger.internal.codegen.javapoet.TypeNames; import dagger.internal.codegen.model.DependencyRequest; import dagger.internal.codegen.model.RequestKind; import dagger.internal.codegen.xprocessing.XTypeNames; import javax.inject.Inject; import javax.lang.model.SourceVersion; /** Utilities for generating files. */ public final class SourceFiles { private static final Joiner CLASS_FILE_NAME_JOINER = Joiner.on('_'); @Inject SourceFiles() {} /** * Generates names and keys for the factory class fields needed to hold the framework classes for * all of the dependencies of {@code binding}. It is responsible for choosing a name that * *
This method is useful during validation before a {@link Binding} can be created. If a * binding already exists for the given element, prefer to call {@link * #generatedClassNameForBinding(Binding)} instead since this method does not validate that the * given element is actually a binding element or not. */ public static XClassName factoryNameForElement(XExecutableElement element) { return elementBasedClassName(element, "Factory"); } /** * Calculates an appropriate {@link XClassName} for a generated class that is based on {@code * element}, appending {@code suffix} at the end. * *
This will always return a top level class name, even if {@code element}'s enclosing class is
* a nested type.
*/
public static XClassName elementBasedClassName(XExecutableElement element, String suffix) {
XClassName enclosingClassName = element.getEnclosingElement().asClassName();
String methodName =
isConstructor(element) ? "" : LOWER_CAMEL.to(UPPER_CAMEL, getSimpleName(element));
return XClassName.Companion.get(
enclosingClassName.getPackageName(),
classFileName(enclosingClassName) + "_" + methodName + suffix);
}
public static TypeName parameterizedGeneratedTypeNameForBinding(Binding binding) {
ClassName className = toJavaPoet(generatedClassNameForBinding(binding));
ImmutableList
*
*/
public static XClassName setFactoryClassName(MultiboundSetBinding binding) {
switch (binding.bindingType()) {
case PROVISION:
return XTypeNames.SET_FACTORY;
case PRODUCTION:
SetType setType = SetType.from(binding.key());
return setType.elementsAreTypeOf(TypeNames.PRODUCED)
? XTypeNames.SET_OF_PRODUCED_PRODUCER
: XTypeNames.SET_PRODUCER;
default:
throw new IllegalArgumentException(binding.bindingType().toString());
}
}
/** The {@link java.util.Map} factory class name appropriate for map bindings. */
public static XClassName mapFactoryClassName(MultiboundMapBinding binding) {
MapType mapType = MapType.from(binding.key());
switch (binding.bindingType()) {
case PROVISION:
return mapType.valuesAreTypeOf(PROVIDER)
? XTypeNames.MAP_PROVIDER_FACTORY : XTypeNames.MAP_FACTORY;
case PRODUCTION:
return mapType.valuesAreFrameworkType()
? mapType.valuesAreTypeOf(PRODUCER)
? XTypeNames.MAP_OF_PRODUCER_PRODUCER
: XTypeNames.MAP_OF_PRODUCED_PRODUCER
: XTypeNames.MAP_PRODUCER;
default:
throw new IllegalArgumentException(binding.bindingType().toString());
}
}
public static ImmutableList