| ronshapiro | 732e502 | 2016-01-07 12:10:55 -0800 | [diff] [blame] | 1 | /* |
| ronshapiro | 5dde42d | 2016-06-17 09:03:35 -0700 | [diff] [blame] | 2 | * Copyright (C) 2016 The Dagger Authors. |
| ronshapiro | 732e502 | 2016-01-07 12:10:55 -0800 | [diff] [blame] | 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 | */ |
| dpb | 1b65b6a | 2016-07-11 12:11:24 -0700 | [diff] [blame] | 16 | |
| ronshapiro | 732e502 | 2016-01-07 12:10:55 -0800 | [diff] [blame] | 17 | package dagger.internal.codegen; |
| 18 | |
| ronshapiro | 57f302c | 2017-02-01 11:35:47 -0800 | [diff] [blame] | 19 | import static dagger.internal.codegen.TypeNames.rawTypeName; |
| gak | 1ab10de | 2017-01-06 12:57:33 -0800 | [diff] [blame] | 20 | import static java.util.stream.StreamSupport.stream; |
| 21 | |
| ronshapiro | 57f302c | 2017-02-01 11:35:47 -0800 | [diff] [blame] | 22 | import com.google.auto.common.MoreElements; |
| gak | 1ab10de | 2017-01-06 12:57:33 -0800 | [diff] [blame] | 23 | import com.google.errorprone.annotations.CanIgnoreReturnValue; |
| ronshapiro | 57f302c | 2017-02-01 11:35:47 -0800 | [diff] [blame] | 24 | import com.squareup.javapoet.ClassName; |
| ronshapiro | 732e502 | 2016-01-07 12:10:55 -0800 | [diff] [blame] | 25 | import com.squareup.javapoet.CodeBlock; |
| gak | 1ab10de | 2017-01-06 12:57:33 -0800 | [diff] [blame] | 26 | import com.squareup.javapoet.CodeBlock.Builder; |
| gak | 00a6fb1 | 2016-11-14 23:33:06 -0800 | [diff] [blame] | 27 | import com.squareup.javapoet.TypeName; |
| gak | 1ab10de | 2017-01-06 12:57:33 -0800 | [diff] [blame] | 28 | import java.util.stream.Collector; |
| gak | 00a6fb1 | 2016-11-14 23:33:06 -0800 | [diff] [blame] | 29 | import javax.lang.model.element.ExecutableElement; |
| 30 | import javax.lang.model.element.VariableElement; |
| ronshapiro | 732e502 | 2016-01-07 12:10:55 -0800 | [diff] [blame] | 31 | |
| 32 | final class CodeBlocks { |
| gak | 1ab10de | 2017-01-06 12:57:33 -0800 | [diff] [blame] | 33 | /** |
| 34 | * A {@link Collector} implementation that joins {@link CodeBlock} instances together into one |
| 35 | * separated by {@code delimiter}. For example, joining {@code String s}, {@code Object o} and |
| 36 | * {@code int i} using {@code ", "} would produce {@code String s, Object o, int i}. |
| 37 | */ |
| 38 | static Collector<CodeBlock, ?, CodeBlock> joiningCodeBlocks(String delimiter) { |
| 39 | return Collector.of( |
| 40 | () -> new CodeBlockJoiner(delimiter, CodeBlock.builder()), |
| 41 | CodeBlockJoiner::add, |
| 42 | CodeBlockJoiner::merge, |
| 43 | CodeBlockJoiner::join); |
| 44 | } |
| 45 | |
| 46 | /** |
| 47 | * Joins {@link CodeBlock} instances in a manner suitable for use as method parameters (or |
| 48 | * arguments). This is equivalent to {@code joiningCodeBlocks(", ")}. |
| 49 | */ |
| 50 | static Collector<CodeBlock, ?, CodeBlock> toParametersCodeBlock() { |
| 51 | return joiningCodeBlocks(", "); |
| 52 | } |
| 53 | |
| 54 | /** |
| 55 | * Joins {@link TypeName} instances into a {@link CodeBlock} that is a comma-separated list for |
| 56 | * use as type parameters or javadoc method arguments. |
| 57 | */ |
| 58 | static Collector<TypeName, ?, CodeBlock> toTypeNamesCodeBlock() { |
| gak | 1ab10de | 2017-01-06 12:57:33 -0800 | [diff] [blame] | 59 | return Collector.of( |
| cushon | f5447bc | 2017-03-01 18:35:39 -0800 | [diff] [blame] | 60 | () -> new CodeBlockJoiner(", ", CodeBlock.builder()), |
| gak | 1ab10de | 2017-01-06 12:57:33 -0800 | [diff] [blame] | 61 | CodeBlockJoiner::addTypeName, |
| 62 | CodeBlockJoiner::merge, |
| 63 | CodeBlockJoiner::join); |
| 64 | } |
| 65 | |
| 66 | /** |
| 67 | * Concatenates {@link CodeBlock} instances separated by newlines for readability. This is |
| 68 | * equivalent to {@code joiningCodeBlocks("\n")}. |
| 69 | */ |
| 70 | static Collector<CodeBlock, ?, CodeBlock> toConcatenatedCodeBlock() { |
| 71 | return joiningCodeBlocks("\n"); |
| 72 | } |
| ronshapiro | 732e502 | 2016-01-07 12:10:55 -0800 | [diff] [blame] | 73 | |
| gak | 00a6fb1 | 2016-11-14 23:33:06 -0800 | [diff] [blame] | 74 | /** Returns a comma-separated version of {@code codeBlocks} as one unified {@link CodeBlock}. */ |
| ronshapiro | 732e502 | 2016-01-07 12:10:55 -0800 | [diff] [blame] | 75 | static CodeBlock makeParametersCodeBlock(Iterable<CodeBlock> codeBlocks) { |
| gak | 1ab10de | 2017-01-06 12:57:33 -0800 | [diff] [blame] | 76 | return stream(codeBlocks.spliterator(), false).collect(toParametersCodeBlock()); |
| 77 | } |
| 78 | |
| 79 | private static final class CodeBlockJoiner { |
| 80 | private final String delimiter; |
| 81 | private final CodeBlock.Builder builder; |
| 82 | private boolean first = true; |
| 83 | |
| 84 | CodeBlockJoiner(String delimiter, Builder builder) { |
| 85 | this.delimiter = delimiter; |
| 86 | this.builder = builder; |
| 87 | } |
| 88 | |
| 89 | @CanIgnoreReturnValue |
| 90 | CodeBlockJoiner add(CodeBlock codeBlock) { |
| 91 | maybeAddDelimiter(); |
| 92 | builder.add(codeBlock); |
| 93 | return this; |
| 94 | } |
| 95 | |
| 96 | @CanIgnoreReturnValue |
| 97 | CodeBlockJoiner addTypeName(TypeName typeName) { |
| 98 | maybeAddDelimiter(); |
| 99 | builder.add("$T", typeName); |
| 100 | return this; |
| 101 | } |
| 102 | |
| 103 | private void maybeAddDelimiter() { |
| 104 | if (!first) { |
| 105 | builder.add(delimiter); |
| 106 | } |
| 107 | first = false; |
| 108 | } |
| 109 | |
| 110 | @CanIgnoreReturnValue |
| 111 | CodeBlockJoiner merge(CodeBlockJoiner other) { |
| 112 | CodeBlock otherBlock = other.builder.build(); |
| 113 | if (!otherBlock.isEmpty()) { |
| 114 | add(otherBlock); |
| 115 | } |
| 116 | return this; |
| 117 | } |
| 118 | |
| 119 | CodeBlock join() { |
| 120 | return builder.build(); |
| 121 | } |
| ronshapiro | 732e502 | 2016-01-07 12:10:55 -0800 | [diff] [blame] | 122 | } |
| 123 | |
| ronshapiro | f22babc | 2016-01-29 12:16:16 -0800 | [diff] [blame] | 124 | /** |
| 125 | * Returns one unified {@link CodeBlock} which joins each item in {@code codeBlocks} with a |
| 126 | * newline. |
| 127 | */ |
| 128 | static CodeBlock concat(Iterable<CodeBlock> codeBlocks) { |
| gak | 1ab10de | 2017-01-06 12:57:33 -0800 | [diff] [blame] | 129 | return stream(codeBlocks.spliterator(), false).collect(toConcatenatedCodeBlock()); |
| ronshapiro | f22babc | 2016-01-29 12:16:16 -0800 | [diff] [blame] | 130 | } |
| 131 | |
| ronshapiro | 6475f47 | 2016-02-02 07:03:10 -0800 | [diff] [blame] | 132 | static CodeBlock stringLiteral(String toWrap) { |
| ronshapiro | b9158d8 | 2016-04-13 11:00:56 -0700 | [diff] [blame] | 133 | return CodeBlock.of("$S", toWrap); |
| ronshapiro | 6475f47 | 2016-02-02 07:03:10 -0800 | [diff] [blame] | 134 | } |
| 135 | |
| gak | 00a6fb1 | 2016-11-14 23:33:06 -0800 | [diff] [blame] | 136 | /** Returns a javadoc {@literal @link} tag that poins to the given {@link ExecutableElement}. */ |
| 137 | static CodeBlock javadocLinkTo(ExecutableElement executableElement) { |
| 138 | CodeBlock.Builder builder = |
| ronshapiro | 57f302c | 2017-02-01 11:35:47 -0800 | [diff] [blame] | 139 | CodeBlock.builder() |
| 140 | .add( |
| 141 | "{@link $T#", |
| 142 | rawTypeName( |
| 143 | ClassName.get(MoreElements.asType(executableElement.getEnclosingElement())))); |
| gak | 00a6fb1 | 2016-11-14 23:33:06 -0800 | [diff] [blame] | 144 | switch (executableElement.getKind()) { |
| 145 | case METHOD: |
| 146 | builder.add("$L", executableElement.getSimpleName()); |
| 147 | break; |
| 148 | case CONSTRUCTOR: |
| 149 | builder.add("$L", executableElement.getEnclosingElement().getSimpleName()); |
| 150 | break; |
| 151 | case STATIC_INIT: |
| 152 | case INSTANCE_INIT: |
| 153 | throw new IllegalArgumentException( |
| 154 | "cannot create a javadoc link to an initializer: " + executableElement); |
| 155 | default: |
| 156 | throw new AssertionError(executableElement.toString()); |
| 157 | } |
| 158 | builder.add("("); |
| cushon | f5447bc | 2017-03-01 18:35:39 -0800 | [diff] [blame] | 159 | builder.add( |
| 160 | executableElement |
| 161 | .getParameters() |
| 162 | .stream() |
| 163 | .map(VariableElement::asType) |
| 164 | .map(TypeName::get) |
| 165 | .map(TypeNames::rawTypeName) |
| 166 | .collect(toTypeNamesCodeBlock())); |
| gak | 00a6fb1 | 2016-11-14 23:33:06 -0800 | [diff] [blame] | 167 | return builder.add(")}").build(); |
| 168 | } |
| 169 | |
| ronshapiro | 732e502 | 2016-01-07 12:10:55 -0800 | [diff] [blame] | 170 | private CodeBlocks() {} |
| 171 | } |