1/*
2 * Copyright (C) 2014 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 */
16package dagger.internal.codegen;
17
18import com.google.auto.value.AutoValue;
19import com.google.common.base.Optional;
20import com.google.common.collect.ImmutableSet;
21import dagger.Component;
22import dagger.internal.codegen.writer.ClassName;
23import dagger.internal.codegen.writer.ClassWriter;
24import dagger.internal.codegen.writer.FieldWriter;
25import dagger.internal.codegen.writer.JavaWriter;
26import dagger.internal.codegen.writer.Snippet;
27import dagger.internal.codegen.writer.TypeName;
28import javax.annotation.processing.Filer;
29import javax.lang.model.element.Element;
30import javax.lang.model.util.Elements;
31import javax.lang.model.util.Types;
32import javax.tools.Diagnostic;
33
34/**
35 * Generates the implementation of the abstract types annotated with {@link Component}.
36 *
37 * @author Gregory Kick
38 * @since 2.0
39 */
40final class ComponentGenerator extends SourceFileGenerator<BindingGraph> {
41  private final Types types;
42  private final Elements elements;
43  private final Key.Factory keyFactory;
44  private final Diagnostic.Kind nullableValidationType;
45
46  ComponentGenerator(
47      Filer filer,
48      Elements elements,
49      Types types,
50      Key.Factory keyFactory,
51      Diagnostic.Kind nullableValidationType) {
52    super(filer);
53    this.types = types;
54    this.elements = elements;
55    this.keyFactory = keyFactory;
56    this.nullableValidationType = nullableValidationType;
57  }
58
59  @Override
60  ClassName nameGeneratedType(BindingGraph input) {
61    ClassName componentDefinitionClassName =
62        ClassName.fromTypeElement(input.componentDescriptor().componentDefinitionType());
63    String componentName = "Dagger" + componentDefinitionClassName.classFileName('_');
64    return componentDefinitionClassName.topLevelClassName().peerNamed(componentName);
65  }
66
67  @Override
68  Iterable<? extends Element> getOriginatingElements(BindingGraph input) {
69    return ImmutableSet.of(input.componentDescriptor().componentDefinitionType());
70  }
71
72  @Override
73  Optional<? extends Element> getElementForErrorReporting(BindingGraph input) {
74    return Optional.of(input.componentDescriptor().componentDefinitionType());
75  }
76
77  @AutoValue static abstract class MemberSelect {
78    static MemberSelect instanceSelect(ClassName owningClass, Snippet snippet) {
79      return new AutoValue_ComponentGenerator_MemberSelect(
80          Optional.<TypeName> absent(), owningClass, false, snippet);
81    }
82
83    static MemberSelect staticSelect(ClassName owningClass, Snippet snippet) {
84      return new AutoValue_ComponentGenerator_MemberSelect(
85          Optional.<TypeName> absent(), owningClass, true, snippet);
86    }
87
88    static MemberSelect staticMethodInvocationWithCast(
89        ClassName owningClass, Snippet snippet, TypeName castType) {
90      return new AutoValue_ComponentGenerator_MemberSelect(
91          Optional.of(castType), owningClass, true, snippet);
92    }
93
94    /**
95     * This exists only to facilitate edge cases in which we need to select a member, but that
96     * member uses a type parameter that can't be inferred.
97     */
98    abstract Optional<TypeName> selectedCast();
99    abstract ClassName owningClass();
100    abstract boolean staticMember();
101    abstract Snippet snippet();
102
103    private Snippet qualifiedSelectSnippet() {
104      return Snippet.format(
105          "%s" + (staticMember() ? "" : ".this") + ".%s",
106          owningClass(), snippet());
107    }
108
109    Snippet getSnippetWithRawTypeCastFor(ClassName usingClass) {
110      Snippet snippet = getSnippetFor(usingClass);
111      return selectedCast().isPresent()
112          ? Snippet.format("(%s) %s", selectedCast().get(), snippet)
113          : snippet;
114    }
115
116    Snippet getSnippetFor(ClassName usingClass) {
117      return owningClass().equals(usingClass) ? snippet() : qualifiedSelectSnippet();
118    }
119  }
120
121  @Override
122  ImmutableSet<JavaWriter> write(ClassName componentName, BindingGraph input) {
123    return new ComponentWriter(
124            types, elements, keyFactory, nullableValidationType, componentName, input)
125        .write();
126  }
127}
128