Home | History | Annotate | Download | only in codegen
      1 /*
      2  * Copyright (C) 2015 Google, Inc.
      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 package dagger.internal.codegen;
     17 
     18 import com.google.auto.common.BasicAnnotationProcessor.ProcessingStep;
     19 import com.google.auto.common.MoreElements;
     20 import com.google.common.collect.ImmutableSet;
     21 import com.google.common.collect.SetMultimap;
     22 import java.lang.annotation.Annotation;
     23 import javax.annotation.processing.Messager;
     24 import javax.lang.model.element.Element;
     25 import javax.lang.model.element.TypeElement;
     26 
     27 /**
     28  * A {@link ProcessingStep} that is responsible for dealing with a component or production component
     29  * as part of the {@link ComponentProcessor}.
     30  */
     31 abstract class AbstractComponentProcessingStep implements ProcessingStep {
     32 
     33   private final Class<? extends Annotation> componentAnnotation;
     34   private final Messager messager;
     35   private final ComponentHierarchyValidator componentHierarchyValidator;
     36   private final BindingGraphValidator bindingGraphValidator;
     37   private final ComponentDescriptor.Factory componentDescriptorFactory;
     38   private final BindingGraph.Factory bindingGraphFactory;
     39   private final ComponentGenerator componentGenerator;
     40 
     41   AbstractComponentProcessingStep(
     42       Class<? extends Annotation> componentAnnotation,
     43       Messager messager,
     44       ComponentHierarchyValidator componentHierarchyValidator,
     45       BindingGraphValidator bindingGraphValidator,
     46       ComponentDescriptor.Factory componentDescriptorFactory,
     47       BindingGraph.Factory bindingGraphFactory,
     48       ComponentGenerator componentGenerator) {
     49     this.componentAnnotation = componentAnnotation;
     50     this.messager = messager;
     51     this.componentHierarchyValidator = componentHierarchyValidator;
     52     this.bindingGraphValidator = bindingGraphValidator;
     53     this.componentDescriptorFactory = componentDescriptorFactory;
     54     this.bindingGraphFactory = bindingGraphFactory;
     55     this.componentGenerator = componentGenerator;
     56   }
     57 
     58   @Override
     59   public final ImmutableSet<Element> process(
     60       SetMultimap<Class<? extends Annotation>, Element> elementsByAnnotation) {
     61     ImmutableSet.Builder<Element> rejectedElements = ImmutableSet.builder();
     62     ComponentElementValidator componentElementValidator =
     63         componentElementValidator(elementsByAnnotation);
     64     for (Element element : elementsByAnnotation.get(componentAnnotation)) {
     65       TypeElement componentTypeElement = MoreElements.asType(element);
     66       try {
     67         if (componentElementValidator.validateComponent(componentTypeElement, messager)) {
     68           ComponentDescriptor componentDescriptor =
     69               componentDescriptorFactory.forComponent(componentTypeElement);
     70           ValidationReport<TypeElement> hierarchyReport =
     71               componentHierarchyValidator.validate(componentDescriptor);
     72           hierarchyReport.printMessagesTo(messager);
     73           if (hierarchyReport.isClean()) {
     74             BindingGraph bindingGraph = bindingGraphFactory.create(componentDescriptor);
     75             ValidationReport<TypeElement> graphReport =
     76                 bindingGraphValidator.validate(bindingGraph);
     77             graphReport.printMessagesTo(messager);
     78             if (graphReport.isClean()) {
     79               generateComponent(bindingGraph);
     80             }
     81           }
     82         }
     83       } catch (TypeNotPresentException e) {
     84         rejectedElements.add(componentTypeElement);
     85       }
     86     }
     87     return rejectedElements.build();
     88   }
     89 
     90   private void generateComponent(BindingGraph bindingGraph) {
     91     try {
     92       componentGenerator.generate(bindingGraph);
     93     } catch (SourceFileGenerationException e) {
     94       e.printMessageTo(messager);
     95     }
     96   }
     97 
     98   /**
     99    * Returns an object that can validate a type element annotated with the component type.
    100    */
    101   protected abstract ComponentElementValidator componentElementValidator(
    102       SetMultimap<Class<? extends Annotation>, Element> elementsByAnnotation);
    103 
    104   /**
    105    * Validates a component type element.
    106    */
    107   protected static abstract class ComponentElementValidator {
    108     /**
    109      * Validates a component type element. Prints any messages about the element to
    110      * {@code messager}.
    111      *
    112      * @throws TypeNotPresentException if any type required to validate the component cannot be
    113      *     found
    114      */
    115     abstract boolean validateComponent(TypeElement componentTypeElement, Messager messager);
    116   }
    117 }
    118