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.android.processor; 18 19 import static com.google.common.base.Preconditions.checkState; 20 import static com.google.common.collect.Sets.difference; 21 import static dagger.internal.codegen.extension.DaggerStreams.toImmutableMap; 22 import static dagger.internal.codegen.extension.DaggerStreams.toImmutableSet; 23 24 import androidx.room.compiler.processing.XElement; 25 import androidx.room.compiler.processing.XProcessingEnv; 26 import androidx.room.compiler.processing.XProcessingStep; 27 import com.google.common.collect.ImmutableMap; 28 import com.google.common.collect.ImmutableSet; 29 import com.google.common.collect.ImmutableSetMultimap; 30 import com.google.common.collect.Maps; 31 import com.squareup.javapoet.ClassName; 32 import java.util.Map; 33 import java.util.Set; 34 35 /** 36 * A {@link XProcessingStep} that processes one element at a time and defers any for which {@link 37 * TypeNotPresentException} is thrown. 38 */ 39 public abstract class BaseProcessingStep implements XProcessingStep { 40 @Override annotations()41 public final ImmutableSet<String> annotations() { 42 return annotationClassNames().stream().map(ClassName::canonicalName).collect(toImmutableSet()); 43 } 44 45 // Subclass must ensure all annotated targets are of valid type. 46 @Override process( XProcessingEnv env, Map<String, ? extends Set<? extends XElement>> elementsByAnnotation)47 public ImmutableSet<XElement> process( 48 XProcessingEnv env, Map<String, ? extends Set<? extends XElement>> elementsByAnnotation) { 49 ImmutableSet.Builder<XElement> deferredElements = ImmutableSet.builder(); 50 inverse(elementsByAnnotation) 51 .forEach( 52 (element, annotations) -> { 53 try { 54 process(element, annotations); 55 } catch (TypeNotPresentException e) { 56 deferredElements.add(element); 57 } 58 }); 59 return deferredElements.build(); 60 } 61 62 /** 63 * Processes one element. If this method throws {@link TypeNotPresentException}, the element will 64 * be deferred until the next round of processing. 65 * 66 * @param annotations the subset of {@link XProcessingStep#annotations()} that annotate {@code 67 * element} 68 */ process(XElement element, ImmutableSet<ClassName> annotations)69 protected abstract void process(XElement element, ImmutableSet<ClassName> annotations); 70 inverse( Map<String, ? extends Set<? extends XElement>> elementsByAnnotation)71 private ImmutableMap<XElement, ImmutableSet<ClassName>> inverse( 72 Map<String, ? extends Set<? extends XElement>> elementsByAnnotation) { 73 ImmutableMap<String, ClassName> annotationClassNames = 74 annotationClassNames().stream() 75 .collect(toImmutableMap(ClassName::canonicalName, className -> className)); 76 checkState( 77 annotationClassNames.keySet().containsAll(elementsByAnnotation.keySet()), 78 "Unexpected annotations for %s: %s", 79 this.getClass().getCanonicalName(), 80 difference(elementsByAnnotation.keySet(), annotationClassNames.keySet())); 81 82 ImmutableSetMultimap.Builder<XElement, ClassName> builder = ImmutableSetMultimap.builder(); 83 elementsByAnnotation.forEach( 84 (annotationName, elementSet) -> 85 elementSet.forEach( 86 element -> builder.put(element, annotationClassNames.get(annotationName)))); 87 88 return ImmutableMap.copyOf(Maps.transformValues(builder.build().asMap(), ImmutableSet::copyOf)); 89 } 90 91 /** Returns the set of annotations processed by this processing step. */ annotationClassNames()92 protected abstract Set<ClassName> annotationClassNames(); 93 } 94