/* * Copyright (C) 2014 Google, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package dagger.internal.codegen.writer; import com.google.common.base.Function; import com.google.common.base.Joiner; import com.google.common.collect.FluentIterable; import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableSet; import com.google.common.collect.Iterables; import java.io.IOException; import java.util.Collections; import java.util.Formatter; import java.util.Iterator; import java.util.Set; public abstract class Snippet implements HasClassReferences, Writable { abstract ImmutableSet types(); @Override public String toString() { return Writables.writeToString(this); } @Override public final Set referencedClasses() { return FluentIterable.from(types()) .transformAndConcat( new Function>() { @Override public Set apply(TypeName input) { return input.referencedClasses(); } }) .toSet(); } private static final class BasicSnippet extends Snippet { final String format; final ImmutableSet types; final ImmutableList args; BasicSnippet(String format, ImmutableSet types, ImmutableList args) { this.format = format; this.types = types; this.args = args; } @Override ImmutableSet types() { return types; } @Override public Appendable write(Appendable appendable, Context context) throws IOException { ImmutableList.Builder formattedArgsBuilder = ImmutableList.builder(); for (Object arg : args) { if (arg instanceof Writable) { formattedArgsBuilder.add(((Writable) arg).write(new StringBuilder(), context).toString()); } else { formattedArgsBuilder.add(arg); } } @SuppressWarnings("resource") // intentionally don't close the formatter Formatter formatter = new Formatter(appendable); formatter.format(format, Iterables.toArray(formattedArgsBuilder.build(), Object.class)); return appendable; } } private static final class CompoundSnippet extends Snippet { final String joinToken; final ImmutableList snippets; CompoundSnippet(String joinToken, ImmutableList snippets) { this.joinToken = joinToken; this.snippets = snippets; } @Override ImmutableSet types() { return FluentIterable.from(snippets) .transformAndConcat( new Function>() { @Override public Iterable apply(Snippet input) { return input.types(); } }) .toSet(); } @Override public Appendable write(Appendable appendable, Context context) throws IOException { Iterator snippetIterator = snippets.iterator(); if (snippetIterator.hasNext()) { Snippet firstSnippet = snippetIterator.next(); firstSnippet.write(appendable, context); while (snippetIterator.hasNext()) { Snippet nextSnippet = snippetIterator.next(); appendable.append(joinToken); nextSnippet.write(appendable, context); } } return appendable; } } public static Snippet format(String format, Object... args) { ImmutableSet.Builder types = ImmutableSet.builder(); for (Object arg : args) { if (arg instanceof Snippet) { types.addAll(((Snippet) arg).types()); } if (arg instanceof TypeName) { types.add((TypeName) arg); } if (arg instanceof HasTypeName) { types.add(((HasTypeName) arg).name()); } } return new BasicSnippet(format, types.build(), ImmutableList.copyOf(args)); } public static Snippet format(String format, Iterable args) { return format(format, Iterables.toArray(args, Object.class)); } public static Snippet memberSelectSnippet(Iterable selectors) { return format(Joiner.on('.').join(Collections.nCopies(Iterables.size(selectors), "%s")), selectors); } public static Snippet nullCheck(Object thingToCheck) { return format("if (%s == null) { throw new NullPointerException(); } ", thingToCheck); } public static Snippet nullCheck(Object thingToCheck, String message) { return format("if (%s == null) { throw new NullPointerException(%s); } ", thingToCheck, StringLiteral.forValue(message)); } public static Snippet makeParametersSnippet(Iterable parameterSnippets) { return join(", ", parameterSnippets); } /** * A snippet that concatenates its arguments with each snippet separated by a new line. */ public static Snippet concat(Iterable snippets) { return join("\n", snippets); } /** * A snippet that joins its arguments with {@code joiner}. */ public static Snippet join(String joinToken, Iterable snippets) { return new CompoundSnippet(joinToken, ImmutableList.copyOf(snippets)); } }