blob: 290621ec1969abd7932dcdc38197f4542c67c3fe [file] [log] [blame]
dstrasburg2e206ec2018-08-21 13:00:27 -07001/*
2 * Copyright (C) 2018 The Dagger Authors.
3 *
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
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
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.
15 */
16
17package dagger.internal.codegen;
18
dstrasburg6d2a7ad2018-09-05 08:05:51 -070019import static com.google.common.base.Preconditions.checkArgument;
dstrasburg2e206ec2018-08-21 13:00:27 -070020import static com.google.common.base.Preconditions.checkState;
dstrasburg6d2a7ad2018-09-05 08:05:51 -070021import static dagger.internal.codegen.DaggerStreams.toImmutableList;
dstrasburg2e206ec2018-08-21 13:00:27 -070022
23import com.google.auto.value.AutoValue;
24import com.google.common.collect.ImmutableList;
25import com.google.common.collect.Maps;
26import com.google.common.collect.Sets;
27import com.squareup.javapoet.MethodSpec;
28import dagger.model.Key;
29import dagger.model.RequestKind;
30import java.util.Map;
dstrasburg6d2a7ad2018-09-05 08:05:51 -070031import java.util.Optional;
dstrasburg2e206ec2018-08-21 13:00:27 -070032import java.util.Set;
33
34/**
35 * A registry for those methods which each wrap a binding whose definition may be modified across
36 * each class in the class hierarchy implementing a subcomponent. Subcomponent implementations are
37 * spread across a class hierarchy when generating ahead-of-time subcomponents. There is one
38 * subcomponent implementation class for each of the subcomponent's ancestor components. An instance
39 * of {@link ModifiableBindingMethod} is associated with a single class in this hierarchy. For a
40 * given subcomponent implementation class we can use the {@link ModifiableBindingMethod}s of its
41 * superclasses to know what binding methods to attempt to modify.
42 */
43final class ModifiableBindingMethods {
dstrasburg6d2a7ad2018-09-05 08:05:51 -070044 private final Map<KeyAndKind, ModifiableBindingMethod> methods = Maps.newLinkedHashMap();
dstrasburg2e206ec2018-08-21 13:00:27 -070045 private final Set<KeyAndKind> finalizedMethods = Sets.newHashSet();
46
47 /** Register a method encapsulating a modifiable binding. */
48 void addMethod(
dstrasburg6d2a7ad2018-09-05 08:05:51 -070049 ModifiableBindingType type, Key key, RequestKind kind, MethodSpec method, boolean finalized) {
50 checkArgument(type.isModifiable());
dstrasburg2e206ec2018-08-21 13:00:27 -070051 KeyAndKind keyAndKind = KeyAndKind.create(key, kind);
dstrasburg6d2a7ad2018-09-05 08:05:51 -070052 if (finalized) {
53 finalizedMethods.add(keyAndKind);
54 }
55 methods.put(keyAndKind, ModifiableBindingMethod.create(type, key, kind, method, finalized));
dstrasburg2e206ec2018-08-21 13:00:27 -070056 }
57
dstrasburg6d2a7ad2018-09-05 08:05:51 -070058 /** Returns all {@link ModifiableBindingMethod}s that have not been marked as finalized. */
59 ImmutableList<ModifiableBindingMethod> getNonFinalizedMethods() {
60 return methods.values().stream().filter(m -> !m.finalized()).collect(toImmutableList());
61 }
62
63 /** Returns the {@link ModifiableBindingMethod} for the given binding if present. */
64 Optional<ModifiableBindingMethod> getMethod(Key key, RequestKind kind) {
65 return Optional.ofNullable(methods.get(KeyAndKind.create(key, kind)));
dstrasburg2e206ec2018-08-21 13:00:27 -070066 }
67
68 /**
69 * Mark the {@link ModifiableBindingMethod} as having been implemented, thus modifying the
dstrasburg6d2a7ad2018-09-05 08:05:51 -070070 * binding.
dstrasburg2e206ec2018-08-21 13:00:27 -070071 */
72 void methodImplemented(ModifiableBindingMethod method) {
dstrasburg6d2a7ad2018-09-05 08:05:51 -070073 if (method.finalized()) {
dstrasburg2e206ec2018-08-21 13:00:27 -070074 checkState(
dstrasburg6d2a7ad2018-09-05 08:05:51 -070075 finalizedMethods.add(KeyAndKind.create(method.key(), method.kind())),
76 "Implementing and finalizing a modifiable binding method that has been marked as "
77 + "finalized in the current subcomponent implementation. The binding is for a %s-%s "
78 + "of type %s.",
dstrasburg2e206ec2018-08-21 13:00:27 -070079 method.key(),
80 method.kind(),
81 method.type());
dstrasburg2e206ec2018-08-21 13:00:27 -070082 }
83 }
84
85 /** Whether a given binding has been marked as finalized. */
dstrasburg6d2a7ad2018-09-05 08:05:51 -070086 boolean finalized(ModifiableBindingMethod method) {
dstrasburg2e206ec2018-08-21 13:00:27 -070087 return finalizedMethods.contains(KeyAndKind.create(method.key(), method.kind()));
88 }
89
90 @AutoValue
91 abstract static class ModifiableBindingMethod {
92 private static ModifiableBindingMethod create(
dstrasburg6d2a7ad2018-09-05 08:05:51 -070093 ModifiableBindingType type,
94 Key key,
95 RequestKind kind,
96 MethodSpec methodSpec,
97 boolean finalized) {
dstrasburg2e206ec2018-08-21 13:00:27 -070098 return new AutoValue_ModifiableBindingMethods_ModifiableBindingMethod(
dstrasburg6d2a7ad2018-09-05 08:05:51 -070099 type, key, kind, methodSpec, finalized);
100 }
101
102 /** Create a {@ModifiableBindingMethod} representing an implementation of an existing method. */
103 static ModifiableBindingMethod implement(
104 ModifiableBindingMethod unimplementedMethod, MethodSpec methodSpec, boolean finalized) {
105 return new AutoValue_ModifiableBindingMethods_ModifiableBindingMethod(
106 unimplementedMethod.type(),
107 unimplementedMethod.key(),
108 unimplementedMethod.kind(),
109 methodSpec,
110 finalized);
dstrasburg2e206ec2018-08-21 13:00:27 -0700111 }
112
113 abstract ModifiableBindingType type();
114
115 abstract Key key();
116
117 abstract RequestKind kind();
118
dstrasburg6d2a7ad2018-09-05 08:05:51 -0700119 abstract MethodSpec methodSpec();
120
121 abstract boolean finalized();
dstrasburg2e206ec2018-08-21 13:00:27 -0700122 }
123
124 @AutoValue
125 abstract static class KeyAndKind {
126 private static KeyAndKind create(Key key, RequestKind kind) {
127 return new AutoValue_ModifiableBindingMethods_KeyAndKind(key, kind);
128 }
129
130 abstract Key key();
131
132 abstract RequestKind kind();
133 }
134}