1 /* 2 * Copyright (C) 2020 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.hilt.processor.internal.aliasof; 18 19 import static com.google.common.base.Suppliers.memoize; 20 21 import com.google.common.base.Preconditions; 22 import com.google.common.base.Supplier; 23 import com.google.common.collect.ImmutableMultimap; 24 import com.google.common.collect.ImmutableSet; 25 import com.squareup.javapoet.ClassName; 26 import dagger.hilt.processor.internal.ClassNames; 27 import dagger.hilt.processor.internal.ProcessorErrors; 28 import dagger.hilt.processor.internal.Processors; 29 import java.util.List; 30 import javax.annotation.processing.ProcessingEnvironment; 31 import javax.lang.model.element.AnnotationMirror; 32 import javax.lang.model.element.Element; 33 import javax.lang.model.element.ElementKind; 34 import javax.lang.model.element.PackageElement; 35 import javax.lang.model.element.TypeElement; 36 import javax.lang.model.util.Elements; 37 38 /** 39 * Extracts a multimap of aliases annotated with {@link dagger.hilt.migration.AliasOf} mapping them 40 * to scopes they are alias of. 41 */ 42 public final class AliasOfs { 43 static final String AGGREGATING_PACKAGE = AliasOfs.class.getPackage().getName() + ".codegen"; 44 45 private final ProcessingEnvironment processingEnvironment; 46 private final ImmutableSet<ClassName> defineComponentScopes; 47 private final Supplier<ImmutableMultimap<ClassName, ClassName>> aliases = 48 memoize(() -> getAliases()); 49 AliasOfs( ProcessingEnvironment processingEnvironment, ImmutableSet<ClassName> defineComponentScopes)50 public AliasOfs( 51 ProcessingEnvironment processingEnvironment, ImmutableSet<ClassName> defineComponentScopes) { 52 this.defineComponentScopes = defineComponentScopes; 53 this.processingEnvironment = processingEnvironment; 54 } 55 getAliasesFor(ClassName defineComponentScope)56 public ImmutableSet<ClassName> getAliasesFor(ClassName defineComponentScope) { 57 return ImmutableSet.copyOf(aliases.get().get(defineComponentScope)); 58 } 59 getAliases()60 private ImmutableMultimap<ClassName, ClassName> getAliases() { 61 Elements elements = processingEnvironment.getElementUtils(); 62 PackageElement packageElement = elements.getPackageElement(AGGREGATING_PACKAGE); 63 if (packageElement == null) { 64 return ImmutableMultimap.of(); 65 } 66 List<? extends Element> scopeAliasElements = packageElement.getEnclosedElements(); 67 Preconditions.checkState( 68 !scopeAliasElements.isEmpty(), "No scope aliases Found in package %s.", packageElement); 69 70 ImmutableMultimap.Builder<ClassName, ClassName> builder = ImmutableMultimap.builder(); 71 for (Element element : scopeAliasElements) { 72 ProcessorErrors.checkState( 73 element.getKind() == ElementKind.CLASS, 74 element, 75 "Only classes may be in package %s. Did you add custom code in the package?", 76 packageElement); 77 78 AnnotationMirror annotationMirror = 79 Processors.getAnnotationMirror(element, ClassNames.ALIAS_OF_PROPAGATED_DATA); 80 81 ProcessorErrors.checkState( 82 annotationMirror != null, 83 element, 84 "Classes in package %s must be annotated with @%s: %s." 85 + " Found: %s. Files in this package are generated, did you add custom code in the" 86 + " package? ", 87 packageElement, 88 ClassNames.ALIAS_OF_PROPAGATED_DATA, 89 element.getSimpleName(), 90 element.getAnnotationMirrors()); 91 92 TypeElement defineComponentScope = 93 Processors.getAnnotationClassValue(elements, annotationMirror, "defineComponentScope"); 94 TypeElement alias = Processors.getAnnotationClassValue(elements, annotationMirror, "alias"); 95 96 Preconditions.checkState( 97 defineComponentScopes.contains(ClassName.get(defineComponentScope)), 98 "The scope %s cannot be an alias for %s. You can only have aliases of a scope defined" 99 + " directly on a @DefineComponent type.", 100 ClassName.get(alias), 101 ClassName.get(defineComponentScope)); 102 103 builder.put(ClassName.get(defineComponentScope), ClassName.get(alias)); 104 } 105 106 return builder.build(); 107 } 108 } 109