blob: 8b6b4a0d7ffd5c5e21b5e4723dcec02d49def6b6 [file] [log] [blame]
ronshapiro732e5022016-01-07 12:10:55 -08001/*
ronshapiro5dde42d2016-06-17 09:03:35 -07002 * Copyright (C) 2016 The Dagger Authors.
ronshapiro732e5022016-01-07 12:10:55 -08003 *
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 */
dpb1b65b6a2016-07-11 12:11:24 -070016
ronshapiro732e5022016-01-07 12:10:55 -080017package dagger.internal.codegen;
18
ronshapiro57f302c2017-02-01 11:35:47 -080019import static dagger.internal.codegen.TypeNames.rawTypeName;
gak1ab10de2017-01-06 12:57:33 -080020import static java.util.stream.StreamSupport.stream;
21
ronshapiro57f302c2017-02-01 11:35:47 -080022import com.google.auto.common.MoreElements;
dpbc8c6c052017-07-28 10:48:06 -070023import com.google.auto.common.MoreTypes;
gak1ab10de2017-01-06 12:57:33 -080024import com.google.errorprone.annotations.CanIgnoreReturnValue;
ronshapiro57f302c2017-02-01 11:35:47 -080025import com.squareup.javapoet.ClassName;
ronshapiro732e5022016-01-07 12:10:55 -080026import com.squareup.javapoet.CodeBlock;
gak1ab10de2017-01-06 12:57:33 -080027import com.squareup.javapoet.CodeBlock.Builder;
dpbc8c6c052017-07-28 10:48:06 -070028import com.squareup.javapoet.MethodSpec;
gak00a6fb12016-11-14 23:33:06 -080029import com.squareup.javapoet.TypeName;
gak1ab10de2017-01-06 12:57:33 -080030import java.util.stream.Collector;
gak00a6fb12016-11-14 23:33:06 -080031import javax.lang.model.element.ExecutableElement;
32import javax.lang.model.element.VariableElement;
dpbc8c6c052017-07-28 10:48:06 -070033import javax.lang.model.type.DeclaredType;
ronshapiro732e5022016-01-07 12:10:55 -080034
35final class CodeBlocks {
gak1ab10de2017-01-06 12:57:33 -080036 /**
37 * A {@link Collector} implementation that joins {@link CodeBlock} instances together into one
38 * separated by {@code delimiter}. For example, joining {@code String s}, {@code Object o} and
39 * {@code int i} using {@code ", "} would produce {@code String s, Object o, int i}.
40 */
41 static Collector<CodeBlock, ?, CodeBlock> joiningCodeBlocks(String delimiter) {
42 return Collector.of(
43 () -> new CodeBlockJoiner(delimiter, CodeBlock.builder()),
44 CodeBlockJoiner::add,
45 CodeBlockJoiner::merge,
46 CodeBlockJoiner::join);
47 }
48
49 /**
50 * Joins {@link CodeBlock} instances in a manner suitable for use as method parameters (or
51 * arguments). This is equivalent to {@code joiningCodeBlocks(", ")}.
52 */
53 static Collector<CodeBlock, ?, CodeBlock> toParametersCodeBlock() {
54 return joiningCodeBlocks(", ");
55 }
56
57 /**
58 * Joins {@link TypeName} instances into a {@link CodeBlock} that is a comma-separated list for
59 * use as type parameters or javadoc method arguments.
60 */
61 static Collector<TypeName, ?, CodeBlock> toTypeNamesCodeBlock() {
gak1ab10de2017-01-06 12:57:33 -080062 return Collector.of(
cushonf5447bc2017-03-01 18:35:39 -080063 () -> new CodeBlockJoiner(", ", CodeBlock.builder()),
gak1ab10de2017-01-06 12:57:33 -080064 CodeBlockJoiner::addTypeName,
65 CodeBlockJoiner::merge,
66 CodeBlockJoiner::join);
67 }
68
69 /**
70 * Concatenates {@link CodeBlock} instances separated by newlines for readability. This is
71 * equivalent to {@code joiningCodeBlocks("\n")}.
72 */
73 static Collector<CodeBlock, ?, CodeBlock> toConcatenatedCodeBlock() {
74 return joiningCodeBlocks("\n");
75 }
ronshapiro732e5022016-01-07 12:10:55 -080076
gak00a6fb12016-11-14 23:33:06 -080077 /** Returns a comma-separated version of {@code codeBlocks} as one unified {@link CodeBlock}. */
ronshapiro732e5022016-01-07 12:10:55 -080078 static CodeBlock makeParametersCodeBlock(Iterable<CodeBlock> codeBlocks) {
gak1ab10de2017-01-06 12:57:33 -080079 return stream(codeBlocks.spliterator(), false).collect(toParametersCodeBlock());
80 }
81
dpbc8c6c052017-07-28 10:48:06 -070082 /** Adds an annotation to a method. */
83 static void addAnnotation(MethodSpec.Builder method, DeclaredType nullableType) {
84 method.addAnnotation(ClassName.get(MoreTypes.asTypeElement(nullableType)));
85 }
86
gak1ab10de2017-01-06 12:57:33 -080087 private static final class CodeBlockJoiner {
88 private final String delimiter;
89 private final CodeBlock.Builder builder;
90 private boolean first = true;
91
92 CodeBlockJoiner(String delimiter, Builder builder) {
93 this.delimiter = delimiter;
94 this.builder = builder;
95 }
96
97 @CanIgnoreReturnValue
98 CodeBlockJoiner add(CodeBlock codeBlock) {
99 maybeAddDelimiter();
100 builder.add(codeBlock);
101 return this;
102 }
103
104 @CanIgnoreReturnValue
105 CodeBlockJoiner addTypeName(TypeName typeName) {
106 maybeAddDelimiter();
107 builder.add("$T", typeName);
108 return this;
109 }
110
111 private void maybeAddDelimiter() {
112 if (!first) {
113 builder.add(delimiter);
114 }
115 first = false;
116 }
117
118 @CanIgnoreReturnValue
119 CodeBlockJoiner merge(CodeBlockJoiner other) {
120 CodeBlock otherBlock = other.builder.build();
121 if (!otherBlock.isEmpty()) {
122 add(otherBlock);
123 }
124 return this;
125 }
126
127 CodeBlock join() {
128 return builder.build();
129 }
ronshapiro732e5022016-01-07 12:10:55 -0800130 }
131
ronshapirof22babc2016-01-29 12:16:16 -0800132 /**
133 * Returns one unified {@link CodeBlock} which joins each item in {@code codeBlocks} with a
134 * newline.
135 */
136 static CodeBlock concat(Iterable<CodeBlock> codeBlocks) {
gak1ab10de2017-01-06 12:57:33 -0800137 return stream(codeBlocks.spliterator(), false).collect(toConcatenatedCodeBlock());
ronshapirof22babc2016-01-29 12:16:16 -0800138 }
139
ronshapiro6475f472016-02-02 07:03:10 -0800140 static CodeBlock stringLiteral(String toWrap) {
ronshapirob9158d82016-04-13 11:00:56 -0700141 return CodeBlock.of("$S", toWrap);
ronshapiro6475f472016-02-02 07:03:10 -0800142 }
143
gak00a6fb12016-11-14 23:33:06 -0800144 /** Returns a javadoc {@literal @link} tag that poins to the given {@link ExecutableElement}. */
145 static CodeBlock javadocLinkTo(ExecutableElement executableElement) {
146 CodeBlock.Builder builder =
ronshapiro57f302c2017-02-01 11:35:47 -0800147 CodeBlock.builder()
148 .add(
149 "{@link $T#",
150 rawTypeName(
151 ClassName.get(MoreElements.asType(executableElement.getEnclosingElement()))));
gak00a6fb12016-11-14 23:33:06 -0800152 switch (executableElement.getKind()) {
153 case METHOD:
154 builder.add("$L", executableElement.getSimpleName());
155 break;
156 case CONSTRUCTOR:
157 builder.add("$L", executableElement.getEnclosingElement().getSimpleName());
158 break;
159 case STATIC_INIT:
160 case INSTANCE_INIT:
161 throw new IllegalArgumentException(
162 "cannot create a javadoc link to an initializer: " + executableElement);
163 default:
164 throw new AssertionError(executableElement.toString());
165 }
166 builder.add("(");
cushonf5447bc2017-03-01 18:35:39 -0800167 builder.add(
168 executableElement
169 .getParameters()
170 .stream()
171 .map(VariableElement::asType)
172 .map(TypeName::get)
173 .map(TypeNames::rawTypeName)
174 .collect(toTypeNamesCodeBlock()));
gak00a6fb12016-11-14 23:33:06 -0800175 return builder.add(")}").build();
176 }
177
ronshapiro732e5022016-01-07 12:10:55 -0800178 private CodeBlocks() {}
179}