• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2014 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.base;
18 
19 import static androidx.room.compiler.processing.JavaPoetExtKt.addOriginatingElement;
20 import static com.google.common.base.Preconditions.checkNotNull;
21 import static dagger.internal.codegen.javapoet.AnnotationSpecs.Suppression.CAST;
22 import static dagger.internal.codegen.javapoet.AnnotationSpecs.Suppression.DEPRECATION;
23 import static dagger.internal.codegen.javapoet.AnnotationSpecs.Suppression.KOTLIN_INTERNAL;
24 import static dagger.internal.codegen.javapoet.AnnotationSpecs.Suppression.RAWTYPES;
25 import static dagger.internal.codegen.javapoet.AnnotationSpecs.Suppression.UNCHECKED;
26 import static dagger.internal.codegen.javapoet.AnnotationSpecs.Suppression.UNINITIALIZED;
27 import static dagger.internal.codegen.xprocessing.XElements.closestEnclosingTypeElement;
28 
29 import androidx.room.compiler.processing.XElement;
30 import androidx.room.compiler.processing.XFiler;
31 import androidx.room.compiler.processing.XMessager;
32 import androidx.room.compiler.processing.XProcessingEnv;
33 import com.google.common.collect.ImmutableList;
34 import com.google.common.collect.ImmutableSet;
35 import com.squareup.javapoet.AnnotationSpec;
36 import com.squareup.javapoet.JavaFile;
37 import com.squareup.javapoet.TypeSpec;
38 import dagger.internal.DaggerGenerated;
39 import dagger.internal.codegen.javapoet.AnnotationSpecs;
40 import dagger.internal.codegen.javapoet.AnnotationSpecs.Suppression;
41 import java.util.Optional;
42 
43 /**
44  * A template class that provides a framework for properly handling IO while generating source files
45  * from an annotation processor. Particularly, it makes a best effort to ensure that files that fail
46  * to write successfully are deleted.
47  *
48  * @param <T> The input type from which source is to be generated.
49  */
50 public abstract class SourceFileGenerator<T> {
51   private static final String GENERATED_COMMENTS = "https://dagger.dev";
52 
53   private final XFiler filer;
54   private final XProcessingEnv processingEnv;
55 
SourceFileGenerator(XFiler filer, XProcessingEnv processingEnv)56   public SourceFileGenerator(XFiler filer, XProcessingEnv processingEnv) {
57     this.filer = checkNotNull(filer);
58     this.processingEnv = checkNotNull(processingEnv);
59   }
60 
SourceFileGenerator(SourceFileGenerator<T> delegate)61   public SourceFileGenerator(SourceFileGenerator<T> delegate) {
62     this(delegate.filer, delegate.processingEnv);
63   }
64 
65   /** Generates a source file to be compiled for {@code T}. */
generate(T input, XMessager messager)66   public void generate(T input, XMessager messager) {
67     generate(input);
68   }
69 
70   /** Generates a source file to be compiled for {@code T}. */
generate(T input)71   public void generate(T input) {
72     for (TypeSpec.Builder type : topLevelTypes(input)) {
73       filer.write(buildJavaFile(input, type), XFiler.Mode.Isolating);
74     }
75   }
76 
buildJavaFile(T input, TypeSpec.Builder typeSpecBuilder)77   private JavaFile buildJavaFile(T input, TypeSpec.Builder typeSpecBuilder) {
78     XElement originatingElement = originatingElement(input);
79     addOriginatingElement(typeSpecBuilder, originatingElement);
80     typeSpecBuilder.addAnnotation(DaggerGenerated.class);
81     Optional<AnnotationSpec> generatedAnnotation =
82         Optional.ofNullable(processingEnv.findGeneratedAnnotation())
83             .map(
84                 annotation ->
85                     AnnotationSpec.builder(annotation.getClassName())
86                         .addMember("value", "$S", "dagger.internal.codegen.ComponentProcessor")
87                         .addMember("comments", "$S", GENERATED_COMMENTS)
88                         .build());
89     generatedAnnotation.ifPresent(typeSpecBuilder::addAnnotation);
90 
91     // TODO(b/263891456): Remove KOTLIN_INTERNAL and use Object/raw types where necessary.
92     typeSpecBuilder.addAnnotation(
93         AnnotationSpecs.suppressWarnings(
94             ImmutableSet.<Suppression>builder()
95                 .addAll(warningSuppressions())
96                 .add(UNCHECKED, RAWTYPES, KOTLIN_INTERNAL, CAST, DEPRECATION, UNINITIALIZED)
97                 .build()));
98 
99     String packageName = closestEnclosingTypeElement(originatingElement).getPackageName();
100     JavaFile.Builder javaFileBuilder =
101         JavaFile.builder(packageName, typeSpecBuilder.build()).skipJavaLangImports(true);
102     if (!generatedAnnotation.isPresent()) {
103       javaFileBuilder.addFileComment("Generated by Dagger ($L).", GENERATED_COMMENTS);
104     }
105     return javaFileBuilder.build();
106   }
107 
108   /** Returns the originating element of the generating type. */
originatingElement(T input)109   public abstract XElement originatingElement(T input);
110 
111   /**
112    * Returns {@link TypeSpec.Builder types} be generated for {@code T}, or an empty list if no types
113    * should be generated.
114    *
115    * <p>Every type will be generated in its own file.
116    */
topLevelTypes(T input)117   public abstract ImmutableList<TypeSpec.Builder> topLevelTypes(T input);
118 
119   /** Returns {@link Suppression}s that are applied to files generated by this generator. */
120   // TODO(b/134590785): When suppressions are removed locally, remove this and inline the usages
warningSuppressions()121   protected ImmutableSet<Suppression> warningSuppressions() {
122     return ImmutableSet.of();
123   }
124 }
125