Home | History | Annotate | Download | only in writer
      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 
     40   EnumWriter(ClassName name) {
     41     super(name);
     42   }
     43 
     44   public ConstantWriter addConstant(String name) {
     45     ConstantWriter constantWriter = new ConstantWriter(name);
     46     constantWriters.put(name, constantWriter);
     47     return constantWriter;
     48   }
     49 
     50   public ConstructorWriter addConstructor() {
     51     ConstructorWriter constructorWriter = new ConstructorWriter(name.simpleName());
     52     constructorWriters.add(constructorWriter);
     53     return constructorWriter;
     54   }
     55 
     56   @Override
     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 
    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
    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 
    141     private ConstantWriter(String name) {
    142       this.name = name;
    143       this.constructorSnippets = Lists.newArrayList();
    144     }
    145 
    146     ConstantWriter addArgument(Snippet snippet) {
    147       constructorSnippets.add(snippet);
    148       return this;
    149     }
    150 
    151     @Override
    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
    168     public Set<ClassName> referencedClasses() {
    169       return FluentIterable.from(constructorSnippets)
    170           .transformAndConcat(HasClassReferences.COMBINER)
    171           .toSet();
    172     }
    173   }
    174 }
    175