• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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  */
16 package dagger.internal.codegen.writer;
17 
18 import com.google.common.base.Function;
19 import com.google.common.collect.FluentIterable;
20 import com.google.common.collect.ImmutableList;
21 import com.google.common.collect.Lists;
22 import com.google.common.collect.Maps;
23 import com.google.common.collect.Sets;
24 import java.io.IOException;
25 import java.util.Iterator;
26 import java.util.List;
27 import java.util.Map;
28 import java.util.Set;
29 import javax.lang.model.element.Modifier;
30 
31 import static com.google.common.base.Preconditions.checkState;
32 import static javax.lang.model.element.Modifier.PRIVATE;
33 import static javax.lang.model.element.Modifier.PROTECTED;
34 import static javax.lang.model.element.Modifier.PUBLIC;
35 
36 public final class EnumWriter extends TypeWriter {
37   private final Map<String, ConstantWriter> constantWriters = Maps.newLinkedHashMap();
38   private final List<ConstructorWriter> constructorWriters = Lists.newArrayList();
39 
EnumWriter(ClassName name)40   EnumWriter(ClassName name) {
41     super(name);
42   }
43 
addConstant(String name)44   public ConstantWriter addConstant(String name) {
45     ConstantWriter constantWriter = new ConstantWriter(name);
46     constantWriters.put(name, constantWriter);
47     return constantWriter;
48   }
49 
addConstructor()50   public ConstructorWriter addConstructor() {
51     ConstructorWriter constructorWriter = new ConstructorWriter(name.simpleName());
52     constructorWriters.add(constructorWriter);
53     return constructorWriter;
54   }
55 
56   @Override
write(Appendable appendable, Context context)57   public Appendable write(Appendable appendable, Context context) throws IOException {
58     context = context.createSubcontext(FluentIterable.from(nestedTypeWriters)
59         .transform(new Function<TypeWriter, ClassName>() {
60           @Override public ClassName apply(TypeWriter input) {
61             return input.name;
62           }
63         })
64         .toSet());
65     writeAnnotations(appendable, context);
66     writeModifiers(appendable).append("enum ").append(name.simpleName());
67     Iterator<TypeName> implementedTypesIterator = implementedTypes.iterator();
68     if (implementedTypesIterator.hasNext()) {
69       appendable.append(" implements ");
70       implementedTypesIterator.next().write(appendable, context);
71       while (implementedTypesIterator.hasNext()) {
72         appendable.append(", ");
73         implementedTypesIterator.next().write(appendable, context);
74       }
75     }
76     appendable.append(" {");
77 
78     checkState(!constantWriters.isEmpty(), "Cannot write an enum with no constants.");
79     appendable.append('\n');
80     ImmutableList<ConstantWriter> constantWriterList =
81         ImmutableList.copyOf(constantWriters.values());
82     for (ConstantWriter constantWriter
83         : constantWriterList.subList(0, constantWriterList.size() - 1)) {
84       constantWriter.write(appendable, context);
85       appendable.append(",\n");
86     }
87     constantWriterList.get(constantWriterList.size() - 1).write(appendable, context);
88     appendable.append(";\n");
89 
90     if (!fieldWriters.isEmpty()) {
91       appendable.append('\n');
92     }
93     for (VariableWriter fieldWriter : fieldWriters.values()) {
94       fieldWriter.write(new IndentingAppendable(appendable), context).append("\n");
95     }
96     for (ConstructorWriter constructorWriter : constructorWriters) {
97       appendable.append('\n');
98       if (!isDefaultConstructor(constructorWriter)) {
99         constructorWriter.write(new IndentingAppendable(appendable), context);
100       }
101     }
102     for (MethodWriter methodWriter : methodWriters) {
103       appendable.append('\n');
104       methodWriter.write(new IndentingAppendable(appendable), context);
105     }
106     for (TypeWriter nestedTypeWriter : nestedTypeWriters) {
107       appendable.append('\n');
108       nestedTypeWriter.write(new IndentingAppendable(appendable), context);
109     }
110     appendable.append("}\n");
111     return appendable;
112   }
113 
114   private static final Set<Modifier> VISIBILIY_MODIFIERS =
115       Sets.immutableEnumSet(PUBLIC, PROTECTED, PRIVATE);
116 
isDefaultConstructor(ConstructorWriter constructorWriter)117   private boolean isDefaultConstructor(ConstructorWriter constructorWriter) {
118     return Sets.intersection(VISIBILIY_MODIFIERS, modifiers)
119         .equals(Sets.intersection(VISIBILIY_MODIFIERS, constructorWriter.modifiers))
120         && constructorWriter.body().isEmpty();
121   }
122 
123   @Override
referencedClasses()124   public Set<ClassName> referencedClasses() {
125     return FluentIterable.from(ImmutableList.<HasClassReferences>of())
126         .append(nestedTypeWriters)
127         .append(constantWriters.values())
128         .append(fieldWriters.values())
129         .append(constructorWriters)
130         .append(methodWriters)
131         .append(implementedTypes)
132         .append(annotations)
133         .transformAndConcat(HasClassReferences.COMBINER)
134         .toSet();
135   }
136 
137   public static final class ConstantWriter implements Writable, HasClassReferences {
138     private final String name;
139     private final List<Snippet> constructorSnippets;
140 
ConstantWriter(String name)141     private ConstantWriter(String name) {
142       this.name = name;
143       this.constructorSnippets = Lists.newArrayList();
144     }
145 
addArgument(Snippet snippet)146     ConstantWriter addArgument(Snippet snippet) {
147       constructorSnippets.add(snippet);
148       return this;
149     }
150 
151     @Override
write(Appendable appendable, Context context)152     public Appendable write(Appendable appendable, Context context) throws IOException {
153       appendable.append(name);
154       Iterator<Snippet> snippetIterator = constructorSnippets.iterator();
155       if (snippetIterator.hasNext()) {
156         appendable.append('(');
157         snippetIterator.next().write(appendable, context);
158         while (snippetIterator.hasNext()) {
159           appendable.append(", ");
160           snippetIterator.next().write(appendable, context);
161         }
162         appendable.append(')');
163       }
164       return appendable;
165     }
166 
167     @Override
referencedClasses()168     public Set<ClassName> referencedClasses() {
169       return FluentIterable.from(constructorSnippets)
170           .transformAndConcat(HasClassReferences.COMBINER)
171           .toSet();
172     }
173   }
174 }
175