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.base.Joiner;
     20 import com.google.common.collect.FluentIterable;
     21 import com.google.common.collect.ImmutableList;
     22 import com.google.common.collect.ImmutableSet;
     23 import com.google.common.collect.Iterables;
     24 import java.io.IOException;
     25 import java.util.Collections;
     26 import java.util.Formatter;
     27 import java.util.Iterator;
     28 import java.util.Set;
     29 
     30 public abstract class Snippet implements HasClassReferences, Writable {
     31 
     32   abstract ImmutableSet<TypeName> types();
     33 
     34   @Override
     35   public String toString() {
     36     return Writables.writeToString(this);
     37   }
     38 
     39   @Override
     40   public final Set<ClassName> referencedClasses() {
     41     return FluentIterable.from(types())
     42         .transformAndConcat(
     43             new Function<TypeName, Set<ClassName>>() {
     44               @Override
     45               public Set<ClassName> apply(TypeName input) {
     46                 return input.referencedClasses();
     47               }
     48             })
     49         .toSet();
     50   }
     51 
     52   private static final class BasicSnippet extends Snippet {
     53     final String format;
     54     final ImmutableSet<TypeName> types;
     55     final ImmutableList<Object> args;
     56 
     57     BasicSnippet(String format, ImmutableSet<TypeName> types, ImmutableList<Object> args) {
     58       this.format = format;
     59       this.types = types;
     60       this.args = args;
     61     }
     62 
     63     @Override
     64     ImmutableSet<TypeName> types() {
     65       return types;
     66     }
     67 
     68     @Override
     69     public Appendable write(Appendable appendable, Context context) throws IOException {
     70       ImmutableList.Builder<Object> formattedArgsBuilder = ImmutableList.builder();
     71       for (Object arg : args) {
     72         if (arg instanceof Writable) {
     73           formattedArgsBuilder.add(((Writable) arg).write(new StringBuilder(), context).toString());
     74         } else {
     75           formattedArgsBuilder.add(arg);
     76         }
     77       }
     78 
     79       @SuppressWarnings("resource") // intentionally don't close the formatter
     80       Formatter formatter = new Formatter(appendable);
     81       formatter.format(format, Iterables.toArray(formattedArgsBuilder.build(), Object.class));
     82 
     83       return appendable;
     84     }
     85   }
     86 
     87   private static final class CompoundSnippet extends Snippet {
     88     final String joinToken;
     89     final ImmutableList<Snippet> snippets;
     90 
     91     CompoundSnippet(String joinToken, ImmutableList<Snippet> snippets) {
     92       this.joinToken = joinToken;
     93       this.snippets = snippets;
     94     }
     95 
     96     @Override
     97     ImmutableSet<TypeName> types() {
     98       return FluentIterable.from(snippets)
     99           .transformAndConcat(
    100               new Function<Snippet, Iterable<TypeName>>() {
    101                 @Override
    102                 public Iterable<TypeName> apply(Snippet input) {
    103                   return input.types();
    104                 }
    105               })
    106           .toSet();
    107     }
    108 
    109     @Override
    110     public Appendable write(Appendable appendable, Context context) throws IOException {
    111       Iterator<Snippet> snippetIterator = snippets.iterator();
    112       if (snippetIterator.hasNext()) {
    113         Snippet firstSnippet = snippetIterator.next();
    114         firstSnippet.write(appendable, context);
    115         while (snippetIterator.hasNext()) {
    116           Snippet nextSnippet = snippetIterator.next();
    117           appendable.append(joinToken);
    118           nextSnippet.write(appendable, context);
    119         }
    120       }
    121       return appendable;
    122     }
    123   }
    124 
    125   public static Snippet format(String format, Object... args) {
    126     ImmutableSet.Builder<TypeName> types = ImmutableSet.builder();
    127     for (Object arg : args) {
    128       if (arg instanceof Snippet) {
    129         types.addAll(((Snippet) arg).types());
    130       }
    131       if (arg instanceof TypeName) {
    132         types.add((TypeName) arg);
    133       }
    134       if (arg instanceof HasTypeName) {
    135         types.add(((HasTypeName) arg).name());
    136       }
    137     }
    138     return new BasicSnippet(format, types.build(), ImmutableList.copyOf(args));
    139   }
    140 
    141   public static Snippet format(String format, Iterable<? extends Object> args) {
    142     return format(format, Iterables.toArray(args, Object.class));
    143   }
    144 
    145   public static Snippet memberSelectSnippet(Iterable<? extends Object> selectors) {
    146     return format(Joiner.on('.').join(Collections.nCopies(Iterables.size(selectors), "%s")),
    147         selectors);
    148   }
    149 
    150   public static Snippet nullCheck(Object thingToCheck) {
    151     return format("if (%s == null) { throw new NullPointerException(); } ", thingToCheck);
    152   }
    153 
    154   public static Snippet nullCheck(Object thingToCheck, String message) {
    155     return format("if (%s == null) { throw new NullPointerException(%s); } ",
    156         thingToCheck,
    157         StringLiteral.forValue(message));
    158   }
    159 
    160   public static Snippet makeParametersSnippet(Iterable<Snippet> parameterSnippets) {
    161     return join(", ", parameterSnippets);
    162   }
    163 
    164   /**
    165    * A snippet that concatenates its arguments with each snippet separated by a new line.
    166    */
    167   public static Snippet concat(Iterable<Snippet> snippets) {
    168     return join("\n", snippets);
    169   }
    170 
    171   /**
    172    * A snippet that joins its arguments with {@code joiner}.
    173    */
    174   public static Snippet join(String joinToken, Iterable<Snippet> snippets) {
    175     return new CompoundSnippet(joinToken, ImmutableList.copyOf(snippets));
    176   }
    177 }
    178