• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2023 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 
17 package dagger.internal.codegen.model;
18 
19 import com.google.auto.value.AutoValue;
20 import com.google.auto.value.extension.memoized.Memoized;
21 import com.google.common.base.Joiner;
22 import dagger.internal.codegen.xprocessing.XAnnotations;
23 import dagger.internal.codegen.xprocessing.XElements;
24 import java.util.Optional;
25 
26 /**
27  * A {@linkplain DaggerType type} and an optional {@linkplain javax.inject.Qualifier qualifier} that
28  * is the lookup key for a binding.
29  */
30 @AutoValue
31 public abstract class Key {
32   /**
33    * A {@link javax.inject.Qualifier} annotation that provides a unique namespace prefix for the
34    * type of this key.
35    */
qualifier()36   public abstract Optional<DaggerAnnotation> qualifier();
37 
38   /** The type represented by this key. */
type()39   public abstract DaggerType type();
40 
41   /**
42    * Distinguishes keys for multibinding contributions that share a {@link #type()} and {@link
43    * #qualifier()}.
44    *
45    * <p>Each multibound map and set has a synthetic multibinding that depends on the specific
46    * contributions to that map or set using keys that identify those multibinding contributions.
47    *
48    * <p>Absent except for multibinding contributions.
49    */
multibindingContributionIdentifier()50   public abstract Optional<MultibindingContributionIdentifier> multibindingContributionIdentifier();
51 
52   /** Returns a {@link Builder} that inherits the properties of this key. */
toBuilder()53   abstract Builder toBuilder();
54 
55   /** Returns a copy of this key with the type replaced with the given type. */
withType(DaggerType newType)56   public Key withType(DaggerType newType) {
57     return toBuilder().type(newType).build();
58   }
59 
60   /**
61    * Returns a copy of this key with the multibinding contribution identifier replaced with the
62    * given multibinding contribution identifier.
63    */
withMultibindingContributionIdentifier( DaggerTypeElement contributingModule, DaggerExecutableElement bindingMethod)64   public Key withMultibindingContributionIdentifier(
65       DaggerTypeElement contributingModule, DaggerExecutableElement bindingMethod) {
66     return toBuilder()
67         .multibindingContributionIdentifier(contributingModule, bindingMethod)
68         .build();
69   }
70 
71   /** Returns a copy of this key with the multibinding contribution identifier, if any, removed. */
withoutMultibindingContributionIdentifier()72   public Key withoutMultibindingContributionIdentifier() {
73     return toBuilder().multibindingContributionIdentifier(Optional.empty()).build();
74   }
75 
76   // The main hashCode/equality bottleneck is in MoreTypes.equivalence(). It's possible that we can
77   // avoid this by tuning that method. Perhaps we can also avoid the issue entirely by interning all
78   // Keys
79   @Memoized
80   @Override
hashCode()81   public abstract int hashCode();
82 
83   @Override
equals(Object o)84   public abstract boolean equals(Object o);
85 
86   @Override
toString()87   public final String toString() {
88     return Joiner.on(' ')
89         .skipNulls()
90         .join(
91             qualifier()
92                 .map(DaggerAnnotation::xprocessing)
93                 .map(XAnnotations::toStableString)
94                 .orElse(null),
95             type(),
96             multibindingContributionIdentifier().orElse(null));
97   }
98 
99   /** Returns a builder for {@link Key}s. */
builder(DaggerType type)100   public static Builder builder(DaggerType type) {
101     return new AutoValue_Key.Builder().type(type);
102   }
103 
104   /** A builder for {@link Key}s. */
105   @AutoValue.Builder
106   public abstract static class Builder {
type(DaggerType type)107     public abstract Builder type(DaggerType type);
108 
qualifier(Optional<DaggerAnnotation> qualifier)109     public abstract Builder qualifier(Optional<DaggerAnnotation> qualifier);
110 
qualifier(DaggerAnnotation qualifier)111     public abstract Builder qualifier(DaggerAnnotation qualifier);
112 
multibindingContributionIdentifier( DaggerTypeElement contributingModule, DaggerExecutableElement bindingMethod)113     public final Builder multibindingContributionIdentifier(
114         DaggerTypeElement contributingModule, DaggerExecutableElement bindingMethod) {
115       return multibindingContributionIdentifier(
116           Optional.of(
117               MultibindingContributionIdentifier.create(contributingModule, bindingMethod)));
118     }
119 
multibindingContributionIdentifier( Optional<MultibindingContributionIdentifier> identifier)120     abstract Builder multibindingContributionIdentifier(
121         Optional<MultibindingContributionIdentifier> identifier);
122 
build()123     public abstract Key build();
124   }
125 
126   /**
127    * An object that identifies a multibinding contribution method and the module class that
128    * contributes it to the graph.
129    *
130    * @see #multibindingContributionIdentifier()
131    */
132   @AutoValue
133   public abstract static class MultibindingContributionIdentifier {
create( DaggerTypeElement contributingModule, DaggerExecutableElement bindingMethod)134     private static MultibindingContributionIdentifier create(
135         DaggerTypeElement contributingModule, DaggerExecutableElement bindingMethod) {
136       return new AutoValue_Key_MultibindingContributionIdentifier(
137           contributingModule, bindingMethod);
138     }
139 
140     /** Returns the module containing the multibinding method. */
contributingModule()141     public abstract DaggerTypeElement contributingModule();
142 
143     /** Returns the multibinding method that defines teh multibinding contribution. */
bindingMethod()144     public abstract DaggerExecutableElement bindingMethod();
145 
146     /**
147      * {@inheritDoc}
148      *
149      * <p>The returned string is human-readable and distinguishes the keys in the same way as the
150      * whole object.
151      */
152     @Override
toString()153     public String toString() {
154       return String.format(
155           "%s#%s",
156           contributingModule().xprocessing().getQualifiedName(),
157           XElements.getSimpleName(bindingMethod().xprocessing()));
158     }
159   }
160 }
161