| Christian Edward Gruber | fbb8e4b | 2014-04-15 14:02:34 -0700 | [diff] [blame] | 1 | /* |
| ronshapiro | 5dde42d | 2016-06-17 09:03:35 -0700 | [diff] [blame] | 2 | * Copyright (C) 2014 The Dagger Authors. |
| Christian Edward Gruber | fbb8e4b | 2014-04-15 14:02:34 -0700 | [diff] [blame] | 3 | * |
| ronshapiro | 3a179ec | 2017-04-14 09:22:17 -0700 | [diff] [blame] | 4 | * Licensed under the Apache License, Version 2.0 (the "License"); |
| 5 | * you may not use this file except in compliance with the License. |
| 6 | * You may obtain a copy of the License at |
| Christian Edward Gruber | fbb8e4b | 2014-04-15 14:02:34 -0700 | [diff] [blame] | 7 | * |
| 8 | * http://www.apache.org/licenses/LICENSE-2.0 |
| 9 | * |
| ronshapiro | 3a179ec | 2017-04-14 09:22:17 -0700 | [diff] [blame] | 10 | * Unless required by applicable law or agreed to in writing, software |
| 11 | * distributed under the License is distributed on an "AS IS" BASIS, |
| 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| 13 | * See the License for the specific language governing permissions and |
| 14 | * limitations under the License. |
| Christian Edward Gruber | fbb8e4b | 2014-04-15 14:02:34 -0700 | [diff] [blame] | 15 | */ |
| dpb | 1b65b6a | 2016-07-11 12:11:24 -0700 | [diff] [blame] | 16 | |
| Christian Edward Gruber | fbb8e4b | 2014-04-15 14:02:34 -0700 | [diff] [blame] | 17 | package dagger.internal.codegen; |
| 18 | |
| gak | 645274e | 2017-01-04 11:34:17 -0800 | [diff] [blame] | 19 | import static com.google.common.base.CaseFormat.LOWER_CAMEL; |
| gak | e55f074 | 2016-07-12 15:36:42 -0700 | [diff] [blame] | 20 | import static com.google.common.base.CaseFormat.UPPER_CAMEL; |
| 21 | import static com.google.common.base.Preconditions.checkArgument; |
| ronshapiro | b449911 | 2017-08-30 11:34:31 -0700 | [diff] [blame] | 22 | import static com.google.common.base.Preconditions.checkState; |
| gak | 645274e | 2017-01-04 11:34:17 -0800 | [diff] [blame] | 23 | import static com.google.common.base.Verify.verify; |
| dpb | 639bd4d | 2017-10-24 15:15:17 -0700 | [diff] [blame] | 24 | import static dagger.internal.codegen.DaggerStreams.toImmutableList; |
| 25 | import static dagger.internal.codegen.DaggerStreams.toImmutableSet; |
| dpb | ffd98f6 | 2016-12-20 10:05:16 -0800 | [diff] [blame] | 26 | import static dagger.internal.codegen.Optionals.optionalComparator; |
| gak | e55f074 | 2016-07-12 15:36:42 -0700 | [diff] [blame] | 27 | import static dagger.internal.codegen.TypeNames.DOUBLE_CHECK; |
| ronshapiro | 2c9ec49 | 2017-05-26 15:03:38 -0700 | [diff] [blame] | 28 | import static dagger.internal.codegen.TypeNames.MAP_FACTORY; |
| 29 | import static dagger.internal.codegen.TypeNames.MAP_OF_PRODUCED_PRODUCER; |
| 30 | import static dagger.internal.codegen.TypeNames.MAP_OF_PRODUCER_PRODUCER; |
| 31 | import static dagger.internal.codegen.TypeNames.MAP_PRODUCER; |
| 32 | import static dagger.internal.codegen.TypeNames.MAP_PROVIDER_FACTORY; |
| gak | e55f074 | 2016-07-12 15:36:42 -0700 | [diff] [blame] | 33 | import static dagger.internal.codegen.TypeNames.PROVIDER_OF_LAZY; |
| ronshapiro | 2c9ec49 | 2017-05-26 15:03:38 -0700 | [diff] [blame] | 34 | import static dagger.internal.codegen.TypeNames.SET_FACTORY; |
| 35 | import static dagger.internal.codegen.TypeNames.SET_OF_PRODUCED_PRODUCER; |
| 36 | import static dagger.internal.codegen.TypeNames.SET_PRODUCER; |
| ronshapiro | 0c4cddf | 2018-01-04 15:28:51 -0800 | [diff] [blame] | 37 | import static dagger.model.BindingKind.INJECTION; |
| 38 | import static dagger.model.BindingKind.MULTIBOUND_MAP; |
| 39 | import static dagger.model.BindingKind.MULTIBOUND_SET; |
| dpb | ffd98f6 | 2016-12-20 10:05:16 -0800 | [diff] [blame] | 40 | import static java.util.Comparator.comparing; |
| gak | 645274e | 2017-01-04 11:34:17 -0800 | [diff] [blame] | 41 | import static javax.lang.model.SourceVersion.isName; |
| gak | e55f074 | 2016-07-12 15:36:42 -0700 | [diff] [blame] | 42 | |
| ronshapiro | ebf0742 | 2018-03-02 11:41:13 -0800 | [diff] [blame] | 43 | import com.google.auto.common.MoreElements; |
| Christian Edward Gruber | fbb8e4b | 2014-04-15 14:02:34 -0700 | [diff] [blame] | 44 | import com.google.common.base.CaseFormat; |
| ronshapiro | 732e502 | 2016-01-07 12:10:55 -0800 | [diff] [blame] | 45 | import com.google.common.base.Joiner; |
| sameb | 0d49be8 | 2015-01-22 17:29:48 -0800 | [diff] [blame] | 46 | import com.google.common.collect.ImmutableList; |
| Christian Edward Gruber | 2a90069 | 2014-07-01 22:28:26 -0700 | [diff] [blame] | 47 | import com.google.common.collect.ImmutableMap; |
| Christian Edward Gruber | fbb8e4b | 2014-04-15 14:02:34 -0700 | [diff] [blame] | 48 | import com.google.common.collect.ImmutableSet; |
| Christian Edward Gruber | fbb8e4b | 2014-04-15 14:02:34 -0700 | [diff] [blame] | 49 | import com.google.common.collect.Iterables; |
| ronshapiro | e05f921 | 2017-08-08 11:22:11 -0700 | [diff] [blame] | 50 | import com.google.common.collect.Maps; |
| ronshapiro | 6475f47 | 2016-02-02 07:03:10 -0800 | [diff] [blame] | 51 | import com.squareup.javapoet.ClassName; |
| ronshapiro | 732e502 | 2016-01-07 12:10:55 -0800 | [diff] [blame] | 52 | import com.squareup.javapoet.CodeBlock; |
| ronshapiro | e05f921 | 2017-08-08 11:22:11 -0700 | [diff] [blame] | 53 | import com.squareup.javapoet.FieldSpec; |
| ronshapiro | 6475f47 | 2016-02-02 07:03:10 -0800 | [diff] [blame] | 54 | import com.squareup.javapoet.ParameterizedTypeName; |
| 55 | import com.squareup.javapoet.TypeName; |
| ronshapiro | 9540fb2 | 2016-01-13 09:46:47 -0800 | [diff] [blame] | 56 | import com.squareup.javapoet.TypeVariableName; |
| ronshapiro | 2c9ec49 | 2017-05-26 15:03:38 -0700 | [diff] [blame] | 57 | import dagger.internal.SetFactory; |
| ronshapiro | a5023ca | 2018-01-02 12:55:01 -0800 | [diff] [blame] | 58 | import dagger.model.DependencyRequest; |
| ronshapiro | 0a277fd | 2017-12-22 08:30:49 -0800 | [diff] [blame] | 59 | import dagger.model.Key; |
| ronshapiro | 120abc6 | 2017-12-15 09:57:09 -0800 | [diff] [blame] | 60 | import dagger.model.RequestKind; |
| ronshapiro | 2c9ec49 | 2017-05-26 15:03:38 -0700 | [diff] [blame] | 61 | import dagger.producers.Produced; |
| ronshapiro | b449911 | 2017-08-30 11:34:31 -0700 | [diff] [blame] | 62 | import dagger.producers.Producer; |
| ronshapiro | 2c9ec49 | 2017-05-26 15:03:38 -0700 | [diff] [blame] | 63 | import dagger.producers.internal.SetOfProducedProducer; |
| 64 | import dagger.producers.internal.SetProducer; |
| Ron Shapiro | 5f21a80 | 2016-09-21 10:23:55 -0400 | [diff] [blame] | 65 | import java.util.Comparator; |
| Christian Edward Gruber | fbb8e4b | 2014-04-15 14:02:34 -0700 | [diff] [blame] | 66 | import java.util.Iterator; |
| ronshapiro | 0b1bcc6 | 2017-05-26 11:14:20 -0700 | [diff] [blame] | 67 | import java.util.List; |
| ronshapiro | b449911 | 2017-08-30 11:34:31 -0700 | [diff] [blame] | 68 | import javax.inject.Provider; |
| gak | 645274e | 2017-01-04 11:34:17 -0800 | [diff] [blame] | 69 | import javax.lang.model.SourceVersion; |
| gak | 6624110 | 2016-09-13 12:23:00 -0700 | [diff] [blame] | 70 | import javax.lang.model.element.Element; |
| ronshapiro | ebf0742 | 2018-03-02 11:41:13 -0800 | [diff] [blame] | 71 | import javax.lang.model.element.ElementKind; |
| 72 | import javax.lang.model.element.ExecutableElement; |
| Christian Edward Gruber | fbb8e4b | 2014-04-15 14:02:34 -0700 | [diff] [blame] | 73 | import javax.lang.model.element.TypeElement; |
| ronshapiro | 9540fb2 | 2016-01-13 09:46:47 -0800 | [diff] [blame] | 74 | import javax.lang.model.element.TypeParameterElement; |
| Gregory Kick | 03c3c2d | 2014-06-18 17:05:47 -0700 | [diff] [blame] | 75 | |
| Christian Edward Gruber | fbb8e4b | 2014-04-15 14:02:34 -0700 | [diff] [blame] | 76 | /** |
| 77 | * Utilities for generating files. |
| Christian Edward Gruber | fbb8e4b | 2014-04-15 14:02:34 -0700 | [diff] [blame] | 78 | */ |
| 79 | class SourceFiles { |
| ronshapiro | 732e502 | 2016-01-07 12:10:55 -0800 | [diff] [blame] | 80 | |
| ronshapiro | 6475f47 | 2016-02-02 07:03:10 -0800 | [diff] [blame] | 81 | private static final Joiner CLASS_FILE_NAME_JOINER = Joiner.on('_'); |
| ronshapiro | 732e502 | 2016-01-07 12:10:55 -0800 | [diff] [blame] | 82 | |
| Christian Edward Gruber | fbb8e4b | 2014-04-15 14:02:34 -0700 | [diff] [blame] | 83 | /** |
| Christian Edward Gruber | fbb8e4b | 2014-04-15 14:02:34 -0700 | [diff] [blame] | 84 | * Sorts {@link DependencyRequest} instances in an order likely to reflect their logical |
| 85 | * importance. |
| 86 | */ |
| Ron Shapiro | 5f21a80 | 2016-09-21 10:23:55 -0400 | [diff] [blame] | 87 | static final Comparator<DependencyRequest> DEPENDENCY_ORDERING = |
| 88 | // put fields before parameters |
| dpb | ffd98f6 | 2016-12-20 10:05:16 -0800 | [diff] [blame] | 89 | comparing( |
| 90 | (DependencyRequest request) -> request.requestElement().map(Element::getKind), |
| Ron Shapiro | 5f21a80 | 2016-09-21 10:23:55 -0400 | [diff] [blame] | 91 | optionalComparator()) |
| 92 | // order by dependency kind |
| 93 | .thenComparing(DependencyRequest::kind) |
| 94 | // then sort by name |
| 95 | .thenComparing( |
| dpb | ffd98f6 | 2016-12-20 10:05:16 -0800 | [diff] [blame] | 96 | request -> |
| 97 | request.requestElement().map(element -> element.getSimpleName().toString()), |
| Ron Shapiro | 5f21a80 | 2016-09-21 10:23:55 -0400 | [diff] [blame] | 98 | optionalComparator()); |
| Christian Edward Gruber | fbb8e4b | 2014-04-15 14:02:34 -0700 | [diff] [blame] | 99 | |
| sameb | 2ea676a | 2015-01-15 10:20:24 -0800 | [diff] [blame] | 100 | /** |
| dpb | 5719880 | 2015-12-17 12:18:15 -0800 | [diff] [blame] | 101 | * Generates names and keys for the factory class fields needed to hold the framework classes for |
| 102 | * all of the dependencies of {@code binding}. It is responsible for choosing a name that |
| 103 | * |
| Christian Edward Gruber | fbb8e4b | 2014-04-15 14:02:34 -0700 | [diff] [blame] | 104 | * <ul> |
| dpb | 5719880 | 2015-12-17 12:18:15 -0800 | [diff] [blame] | 105 | * <li>represents all of the dependency requests for this key |
| 106 | * <li>is <i>probably</i> associated with the type being bound |
| 107 | * <li>is unique within the class |
| Christian Edward Gruber | fbb8e4b | 2014-04-15 14:02:34 -0700 | [diff] [blame] | 108 | * </ul> |
| Ron Shapiro | 5f21a80 | 2016-09-21 10:23:55 -0400 | [diff] [blame] | 109 | * |
| dpb | 5719880 | 2015-12-17 12:18:15 -0800 | [diff] [blame] | 110 | * @param binding must be an unresolved binding (type parameters must match its type element's) |
| Christian Edward Gruber | fbb8e4b | 2014-04-15 14:02:34 -0700 | [diff] [blame] | 111 | */ |
| ronshapiro | 0a277fd | 2017-12-22 08:30:49 -0800 | [diff] [blame] | 112 | static ImmutableMap<Key, FrameworkField> generateBindingFieldsForDependencies( |
| dpb | f6be7d6 | 2016-01-22 11:43:21 -0800 | [diff] [blame] | 113 | Binding binding) { |
| 114 | checkArgument(!binding.unresolved().isPresent(), "binding must be unresolved: %s", binding); |
| 115 | |
| ronshapiro | 0a277fd | 2017-12-22 08:30:49 -0800 | [diff] [blame] | 116 | ImmutableMap.Builder<Key, FrameworkField> bindingFields = ImmutableMap.builder(); |
| gak | 75b9b72 | 2016-09-29 15:48:40 -0700 | [diff] [blame] | 117 | for (Binding.DependencyAssociation dependencyAssociation : binding.dependencyAssociations()) { |
| 118 | FrameworkDependency frameworkDependency = dependencyAssociation.frameworkDependency(); |
| dpb | f6be7d6 | 2016-01-22 11:43:21 -0800 | [diff] [blame] | 119 | bindingFields.put( |
| ronshapiro | 0a277fd | 2017-12-22 08:30:49 -0800 | [diff] [blame] | 120 | frameworkDependency.key(), |
| dpb | d289ddc | 2016-04-28 13:09:11 -0700 | [diff] [blame] | 121 | FrameworkField.create( |
| 122 | ClassName.get(frameworkDependency.frameworkClass()), |
| ronshapiro | 0a277fd | 2017-12-22 08:30:49 -0800 | [diff] [blame] | 123 | TypeName.get(frameworkDependency.key().type()), |
| gak | 75b9b72 | 2016-09-29 15:48:40 -0700 | [diff] [blame] | 124 | fieldNameForDependency(dependencyAssociation.dependencyRequests()))); |
| Christian Edward Gruber | fbb8e4b | 2014-04-15 14:02:34 -0700 | [diff] [blame] | 125 | } |
| beder | 3e950f3 | 2014-12-19 17:48:47 -0800 | [diff] [blame] | 126 | return bindingFields.build(); |
| Christian Edward Gruber | fbb8e4b | 2014-04-15 14:02:34 -0700 | [diff] [blame] | 127 | } |
| 128 | |
| gak | 75b9b72 | 2016-09-29 15:48:40 -0700 | [diff] [blame] | 129 | private static String fieldNameForDependency(ImmutableSet<DependencyRequest> dependencyRequests) { |
| dpb | f6be7d6 | 2016-01-22 11:43:21 -0800 | [diff] [blame] | 130 | // collect together all of the names that we would want to call the provider |
| 131 | ImmutableSet<String> dependencyNames = |
| ronshapiro | 6d1e6ac | 2017-10-09 09:00:32 -0700 | [diff] [blame] | 132 | dependencyRequests.stream().map(DependencyVariableNamer::name).collect(toImmutableSet()); |
| dpb | f6be7d6 | 2016-01-22 11:43:21 -0800 | [diff] [blame] | 133 | |
| 134 | if (dependencyNames.size() == 1) { |
| 135 | // if there's only one name, great! use it! |
| 136 | return Iterables.getOnlyElement(dependencyNames); |
| 137 | } else { |
| 138 | // in the event that a field is being used for a bunch of deps with different names, |
| 139 | // add all the names together with "And"s in the middle. E.g.: stringAndS |
| 140 | Iterator<String> namesIterator = dependencyNames.iterator(); |
| 141 | String first = namesIterator.next(); |
| 142 | StringBuilder compositeNameBuilder = new StringBuilder(first); |
| 143 | while (namesIterator.hasNext()) { |
| 144 | compositeNameBuilder |
| 145 | .append("And") |
| 146 | .append(CaseFormat.LOWER_CAMEL.to(UPPER_CAMEL, namesIterator.next())); |
| 147 | } |
| 148 | return compositeNameBuilder.toString(); |
| 149 | } |
| 150 | } |
| 151 | |
| ronshapiro | 732e502 | 2016-01-07 12:10:55 -0800 | [diff] [blame] | 152 | static CodeBlock frameworkTypeUsageStatement( |
| ronshapiro | 120abc6 | 2017-12-15 09:57:09 -0800 | [diff] [blame] | 153 | CodeBlock frameworkTypeMemberSelect, RequestKind dependencyKind) { |
| ronshapiro | 732e502 | 2016-01-07 12:10:55 -0800 | [diff] [blame] | 154 | switch (dependencyKind) { |
| 155 | case LAZY: |
| ronshapiro | b9158d8 | 2016-04-13 11:00:56 -0700 | [diff] [blame] | 156 | return CodeBlock.of("$T.lazy($L)", DOUBLE_CHECK, frameworkTypeMemberSelect); |
| ronshapiro | 732e502 | 2016-01-07 12:10:55 -0800 | [diff] [blame] | 157 | case INSTANCE: |
| 158 | case FUTURE: |
| ronshapiro | b9158d8 | 2016-04-13 11:00:56 -0700 | [diff] [blame] | 159 | return CodeBlock.of("$L.get()", frameworkTypeMemberSelect); |
| ronshapiro | 732e502 | 2016-01-07 12:10:55 -0800 | [diff] [blame] | 160 | case PROVIDER: |
| 161 | case PRODUCER: |
| dpb | d8d950a | 2016-08-30 09:24:37 -0700 | [diff] [blame] | 162 | return frameworkTypeMemberSelect; |
| dpb | c9bd6d8 | 2016-04-19 07:25:06 -0700 | [diff] [blame] | 163 | case PROVIDER_OF_LAZY: |
| 164 | return CodeBlock.of("$T.create($L)", PROVIDER_OF_LAZY, frameworkTypeMemberSelect); |
| dpb | d8d950a | 2016-08-30 09:24:37 -0700 | [diff] [blame] | 165 | default: // including PRODUCED |
| 166 | throw new AssertionError(dependencyKind); |
| ronshapiro | 732e502 | 2016-01-07 12:10:55 -0800 | [diff] [blame] | 167 | } |
| 168 | } |
| 169 | |
| dpb | 6bd55de | 2015-09-28 07:58:09 -0700 | [diff] [blame] | 170 | /** |
| ronshapiro | e05f921 | 2017-08-08 11:22:11 -0700 | [diff] [blame] | 171 | * Returns a mapping of {@link DependencyRequest}s to {@link CodeBlock}s that {@linkplain |
| ronshapiro | 120abc6 | 2017-12-15 09:57:09 -0800 | [diff] [blame] | 172 | * #frameworkTypeUsageStatement(CodeBlock, RequestKind) use them}. |
| ronshapiro | e05f921 | 2017-08-08 11:22:11 -0700 | [diff] [blame] | 173 | */ |
| 174 | static ImmutableMap<DependencyRequest, CodeBlock> frameworkFieldUsages( |
| ronshapiro | 0a277fd | 2017-12-22 08:30:49 -0800 | [diff] [blame] | 175 | ImmutableSet<DependencyRequest> dependencies, ImmutableMap<Key, FieldSpec> fields) { |
| ronshapiro | e05f921 | 2017-08-08 11:22:11 -0700 | [diff] [blame] | 176 | return Maps.toMap( |
| 177 | dependencies, |
| 178 | dep -> |
| ronshapiro | 0a277fd | 2017-12-22 08:30:49 -0800 | [diff] [blame] | 179 | frameworkTypeUsageStatement(CodeBlock.of("$N", fields.get(dep.key())), dep.kind())); |
| ronshapiro | e05f921 | 2017-08-08 11:22:11 -0700 | [diff] [blame] | 180 | } |
| 181 | |
| 182 | /** |
| dpb | 6bd55de | 2015-09-28 07:58:09 -0700 | [diff] [blame] | 183 | * Returns the generated factory or members injector name for a binding. |
| 184 | */ |
| 185 | static ClassName generatedClassNameForBinding(Binding binding) { |
| 186 | switch (binding.bindingType()) { |
| Christian Edward Gruber | 4aec5ba | 2014-05-20 19:37:11 -0700 | [diff] [blame] | 187 | case PROVISION: |
| dpb | 6bd55de | 2015-09-28 07:58:09 -0700 | [diff] [blame] | 188 | case PRODUCTION: |
| 189 | ContributionBinding contribution = (ContributionBinding) binding; |
| ronshapiro | 0c4cddf | 2018-01-04 15:28:51 -0800 | [diff] [blame] | 190 | switch (contribution.kind()) { |
| dpb | 6bd55de | 2015-09-28 07:58:09 -0700 | [diff] [blame] | 191 | case INJECTION: |
| 192 | case PROVISION: |
| Ron Shapiro | 5f21a80 | 2016-09-21 10:23:55 -0400 | [diff] [blame] | 193 | case PRODUCTION: |
| ronshapiro | ebf0742 | 2018-03-02 11:41:13 -0800 | [diff] [blame] | 194 | return elementBasedClassName( |
| 195 | MoreElements.asExecutable(binding.bindingElement().get()), "Factory"); |
| dpb | 6bd55de | 2015-09-28 07:58:09 -0700 | [diff] [blame] | 196 | |
| 197 | default: |
| 198 | throw new AssertionError(); |
| 199 | } |
| 200 | |
| 201 | case MEMBERS_INJECTION: |
| dpb | 4955ef9 | 2016-04-29 12:31:14 -0700 | [diff] [blame] | 202 | return membersInjectorNameForType( |
| 203 | ((MembersInjectionBinding) binding).membersInjectedType()); |
| dpb | 6bd55de | 2015-09-28 07:58:09 -0700 | [diff] [blame] | 204 | |
| Christian Edward Gruber | 4aec5ba | 2014-05-20 19:37:11 -0700 | [diff] [blame] | 205 | default: |
| 206 | throw new AssertionError(); |
| 207 | } |
| 208 | } |
| Christian Edward Gruber | 791bd29 | 2014-05-20 19:36:41 -0700 | [diff] [blame] | 209 | |
| ronshapiro | ebf0742 | 2018-03-02 11:41:13 -0800 | [diff] [blame] | 210 | /** |
| 211 | * Calculates an appropriate {@link ClassName} for a generated class that is based on {@code |
| 212 | * element}, appending {@code suffix} at the end. |
| 213 | * |
| 214 | * <p>This will always return a {@linkplain ClassName#topLevelClassName() top level class name}, |
| 215 | * even if {@code element}'s enclosing class is a nested type. |
| 216 | */ |
| 217 | static ClassName elementBasedClassName(ExecutableElement element, String suffix) { |
| 218 | ClassName enclosingClassName = |
| 219 | ClassName.get(MoreElements.asType(element.getEnclosingElement())); |
| 220 | String methodName = |
| 221 | element.getKind().equals(ElementKind.CONSTRUCTOR) |
| 222 | ? "" |
| 223 | : LOWER_CAMEL.to(UPPER_CAMEL, element.getSimpleName().toString()); |
| 224 | return ClassName.get( |
| 225 | enclosingClassName.packageName(), |
| 226 | classFileName(enclosingClassName) + "_" + methodName + suffix); |
| 227 | } |
| 228 | |
| gak | 4d86019 | 2016-10-13 23:41:00 -0700 | [diff] [blame] | 229 | static TypeName parameterizedGeneratedTypeNameForBinding(Binding binding) { |
| ronshapiro | 6475f47 | 2016-02-02 07:03:10 -0800 | [diff] [blame] | 230 | ClassName className = generatedClassNameForBinding(binding); |
| gak | 4d86019 | 2016-10-13 23:41:00 -0700 | [diff] [blame] | 231 | ImmutableList<TypeVariableName> typeParameters = bindingTypeElementTypeVariableNames(binding); |
| 232 | return typeParameters.isEmpty() |
| 233 | ? className |
| 234 | : ParameterizedTypeName.get(className, Iterables.toArray(typeParameters, TypeName.class)); |
| Christian Edward Gruber | 10876b0 | 2014-06-01 11:24:55 -0700 | [diff] [blame] | 235 | } |
| 236 | |
| ronshapiro | 6475f47 | 2016-02-02 07:03:10 -0800 | [diff] [blame] | 237 | static ClassName membersInjectorNameForType(TypeElement typeElement) { |
| ronshapiro | a296c10 | 2016-01-14 12:33:42 -0800 | [diff] [blame] | 238 | return siblingClassName(typeElement, "_MembersInjector"); |
| ronshapiro | 732e502 | 2016-01-07 12:10:55 -0800 | [diff] [blame] | 239 | } |
| 240 | |
| ronshapiro | 6475f47 | 2016-02-02 07:03:10 -0800 | [diff] [blame] | 241 | static String classFileName(ClassName className) { |
| ronshapiro | 732e502 | 2016-01-07 12:10:55 -0800 | [diff] [blame] | 242 | return CLASS_FILE_NAME_JOINER.join(className.simpleNames()); |
| 243 | } |
| 244 | |
| ronshapiro | 6475f47 | 2016-02-02 07:03:10 -0800 | [diff] [blame] | 245 | static ClassName generatedMonitoringModuleName( |
| ronshapiro | a296c10 | 2016-01-14 12:33:42 -0800 | [diff] [blame] | 246 | TypeElement componentElement) { |
| 247 | return siblingClassName(componentElement, "_MonitoringModule"); |
| 248 | } |
| 249 | |
| beder | 893f770 | 2016-02-17 05:22:50 -0800 | [diff] [blame] | 250 | static ClassName generatedProductionExecutorModuleName(TypeElement componentElement) { |
| 251 | return siblingClassName(componentElement, "_ProductionExecutorModule"); |
| 252 | } |
| 253 | |
| ronshapiro | 6475f47 | 2016-02-02 07:03:10 -0800 | [diff] [blame] | 254 | // TODO(ronshapiro): when JavaPoet migration is complete, replace the duplicated code |
| 255 | // which could use this. |
| 256 | private static ClassName siblingClassName(TypeElement typeElement, String suffix) { |
| 257 | ClassName className = ClassName.get(typeElement); |
| ronshapiro | 23527f6 | 2016-04-20 10:33:08 -0700 | [diff] [blame] | 258 | return className.topLevelClassName().peerClass(classFileName(className) + suffix); |
| beder | 0e6f248 | 2015-10-23 08:37:55 -0700 | [diff] [blame] | 259 | } |
| 260 | |
| ronshapiro | 2c9ec49 | 2017-05-26 15:03:38 -0700 | [diff] [blame] | 261 | /** |
| 262 | * The {@link java.util.Set} factory class name appropriate for set bindings. |
| 263 | * |
| 264 | * <ul> |
| 265 | * <li>{@link SetFactory} for provision bindings. |
| 266 | * <li>{@link SetProducer} for production bindings for {@code Set<T>}. |
| 267 | * <li>{@link SetOfProducedProducer} for production bindings for {@code Set<Produced<T>>}. |
| 268 | * </ul> |
| 269 | */ |
| 270 | static ClassName setFactoryClassName(ContributionBinding binding) { |
| ronshapiro | 0c4cddf | 2018-01-04 15:28:51 -0800 | [diff] [blame] | 271 | checkArgument(binding.kind().equals(MULTIBOUND_SET)); |
| ronshapiro | 2c9ec49 | 2017-05-26 15:03:38 -0700 | [diff] [blame] | 272 | if (binding.bindingType().equals(BindingType.PROVISION)) { |
| 273 | return SET_FACTORY; |
| 274 | } else { |
| 275 | SetType setType = SetType.from(binding.key()); |
| 276 | return setType.elementsAreTypeOf(Produced.class) ? SET_OF_PRODUCED_PRODUCER : SET_PRODUCER; |
| 277 | } |
| 278 | } |
| 279 | |
| ronshapiro | b449911 | 2017-08-30 11:34:31 -0700 | [diff] [blame] | 280 | /** The {@link java.util.Map} factory class name appropriate for map bindings. */ |
| ronshapiro | 2c9ec49 | 2017-05-26 15:03:38 -0700 | [diff] [blame] | 281 | static ClassName mapFactoryClassName(ContributionBinding binding) { |
| ronshapiro | 0c4cddf | 2018-01-04 15:28:51 -0800 | [diff] [blame] | 282 | checkState(binding.kind().equals(MULTIBOUND_MAP), binding.kind()); |
| ronshapiro | b449911 | 2017-08-30 11:34:31 -0700 | [diff] [blame] | 283 | MapType mapType = MapType.from(binding.key()); |
| ronshapiro | 2c9ec49 | 2017-05-26 15:03:38 -0700 | [diff] [blame] | 284 | switch (binding.bindingType()) { |
| sraub | e1028b7 | 2017-08-28 18:03:22 -0700 | [diff] [blame] | 285 | case PROVISION: |
| ronshapiro | b449911 | 2017-08-30 11:34:31 -0700 | [diff] [blame] | 286 | return mapType.valuesAreTypeOf(Provider.class) ? MAP_PROVIDER_FACTORY : MAP_FACTORY; |
| 287 | case PRODUCTION: |
| 288 | return mapType.valuesAreFrameworkType() |
| 289 | ? mapType.valuesAreTypeOf(Producer.class) |
| 290 | ? MAP_OF_PRODUCER_PRODUCER |
| 291 | : MAP_OF_PRODUCED_PRODUCER |
| 292 | : MAP_PRODUCER; |
| ronshapiro | 2c9ec49 | 2017-05-26 15:03:38 -0700 | [diff] [blame] | 293 | default: |
| ronshapiro | b449911 | 2017-08-30 11:34:31 -0700 | [diff] [blame] | 294 | throw new IllegalArgumentException(binding.bindingType().toString()); |
| ronshapiro | 2c9ec49 | 2017-05-26 15:03:38 -0700 | [diff] [blame] | 295 | } |
| 296 | } |
| 297 | |
| ronshapiro | 9540fb2 | 2016-01-13 09:46:47 -0800 | [diff] [blame] | 298 | static ImmutableList<TypeVariableName> bindingTypeElementTypeVariableNames(Binding binding) { |
| gak | 4d86019 | 2016-10-13 23:41:00 -0700 | [diff] [blame] | 299 | if (binding instanceof ContributionBinding) { |
| 300 | ContributionBinding contributionBinding = (ContributionBinding) binding; |
| ronshapiro | 0c4cddf | 2018-01-04 15:28:51 -0800 | [diff] [blame] | 301 | if (!contributionBinding.kind().equals(INJECTION) |
| gak | 4d86019 | 2016-10-13 23:41:00 -0700 | [diff] [blame] | 302 | && !contributionBinding.requiresModuleInstance()) { |
| 303 | return ImmutableList.of(); |
| 304 | } |
| 305 | } |
| ronshapiro | 0b1bcc6 | 2017-05-26 11:14:20 -0700 | [diff] [blame] | 306 | List<? extends TypeParameterElement> typeParameters = |
| 307 | binding.bindingTypeElement().get().getTypeParameters(); |
| 308 | return typeParameters.stream().map(TypeVariableName::get).collect(toImmutableList()); |
| ronshapiro | 9540fb2 | 2016-01-13 09:46:47 -0800 | [diff] [blame] | 309 | } |
| 310 | |
| gak | 645274e | 2017-01-04 11:34:17 -0800 | [diff] [blame] | 311 | /** |
| 312 | * Returns a name to be used for variables of the given {@linkplain TypeElement type}. Prefer |
| 313 | * semantically meaningful variable names, but if none can be derived, this will produce something |
| 314 | * readable. |
| 315 | */ |
| 316 | // TODO(gak): maybe this should be a function of TypeMirrors instead of Elements? |
| 317 | static String simpleVariableName(TypeElement typeElement) { |
| 318 | String candidateName = UPPER_CAMEL.to(LOWER_CAMEL, typeElement.getSimpleName().toString()); |
| 319 | String variableName = protectAgainstKeywords(candidateName); |
| 320 | verify(isName(variableName), "'%s' was expected to be a valid variable name"); |
| 321 | return variableName; |
| 322 | } |
| 323 | |
| bcorso | 5f0a143 | 2018-04-16 08:51:58 -0700 | [diff] [blame] | 324 | static String protectAgainstKeywords(String candidateName) { |
| gak | 645274e | 2017-01-04 11:34:17 -0800 | [diff] [blame] | 325 | switch (candidateName) { |
| 326 | case "package": |
| 327 | return "pkg"; |
| 328 | case "boolean": |
| 329 | return "b"; |
| 330 | case "double": |
| 331 | return "d"; |
| 332 | case "byte": |
| 333 | return "b"; |
| 334 | case "int": |
| 335 | return "i"; |
| 336 | case "short": |
| 337 | return "s"; |
| 338 | case "char": |
| 339 | return "c"; |
| 340 | case "void": |
| 341 | return "v"; |
| 342 | case "class": |
| 343 | return "clazz"; |
| 344 | case "float": |
| 345 | return "f"; |
| 346 | case "long": |
| 347 | return "l"; |
| 348 | default: |
| 349 | return SourceVersion.isKeyword(candidateName) ? candidateName + '_' : candidateName; |
| 350 | } |
| 351 | } |
| 352 | |
| Christian Edward Gruber | fbb8e4b | 2014-04-15 14:02:34 -0700 | [diff] [blame] | 353 | private SourceFiles() {} |
| 354 | } |