1 /* 2 * Copyright (C) 2016 The Dagger Authors. 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 17 package dagger.internal.codegen.javapoet; 18 19 import static com.squareup.javapoet.MethodSpec.methodBuilder; 20 import static com.squareup.javapoet.TypeSpec.anonymousClassBuilder; 21 import static dagger.internal.codegen.javapoet.TypeNames.daggerProviderOf; 22 import static dagger.internal.codegen.javapoet.TypeNames.lazyOf; 23 import static java.util.stream.StreamSupport.stream; 24 import static javax.lang.model.element.Modifier.PUBLIC; 25 26 import androidx.room.compiler.processing.XType; 27 import com.squareup.javapoet.ClassName; 28 import com.squareup.javapoet.CodeBlock; 29 import com.squareup.javapoet.ParameterSpec; 30 import com.squareup.javapoet.TypeName; 31 import java.util.stream.Collector; 32 33 /** Convenience methods for creating {@link CodeBlock}s. */ 34 public final class CodeBlocks { 35 /** 36 * Joins {@link CodeBlock} instances in a manner suitable for use as method parameters (or 37 * arguments). 38 */ toParametersCodeBlock()39 public static Collector<CodeBlock, ?, CodeBlock> toParametersCodeBlock() { 40 // TODO(ronshapiro,jakew): consider adding zero-width spaces to help line breaking when the 41 // formatter is off. If not, inline this 42 return CodeBlock.joining(", "); 43 } 44 45 /** Concatenates {@link CodeBlock} instances separated by newlines for readability. */ toConcatenatedCodeBlock()46 public static Collector<CodeBlock, ?, CodeBlock> toConcatenatedCodeBlock() { 47 return CodeBlock.joining("\n", "", "\n"); 48 } 49 50 /** Returns a comma-separated version of {@code codeBlocks} as one unified {@link CodeBlock}. */ makeParametersCodeBlock(Iterable<CodeBlock> codeBlocks)51 public static CodeBlock makeParametersCodeBlock(Iterable<CodeBlock> codeBlocks) { 52 return stream(codeBlocks.spliterator(), false).collect(toParametersCodeBlock()); 53 } 54 55 /** 56 * Returns a comma-separated {@link CodeBlock} using the name of every parameter in {@code 57 * parameters}. 58 */ parameterNames(Iterable<ParameterSpec> parameters)59 public static CodeBlock parameterNames(Iterable<ParameterSpec> parameters) { 60 // TODO(ronshapiro): Add DaggerStreams.stream(Iterable) 61 return stream(parameters.spliterator(), false) 62 .map(p -> CodeBlock.of("$N", p)) 63 .collect(toParametersCodeBlock()); 64 } 65 66 /** 67 * Returns one unified {@link CodeBlock} which joins each item in {@code codeBlocks} with a 68 * newline. 69 */ concat(Iterable<CodeBlock> codeBlocks)70 public static CodeBlock concat(Iterable<CodeBlock> codeBlocks) { 71 return stream(codeBlocks.spliterator(), false).collect(toConcatenatedCodeBlock()); 72 } 73 74 /** 75 * Returns an anonymous {@link javax.inject.Provider} class with the single {@link 76 * javax.inject.Provider#get()} method that returns the given {@code expression}. 77 */ anonymousProvider(Expression expression)78 public static CodeBlock anonymousProvider(Expression expression) { 79 return anonymousProvider( 80 expression.type().getTypeName(), CodeBlock.of("return $L;", expression.codeBlock())); 81 } 82 83 /** 84 * Returns an anonymous {@link javax.inject.Provider} class with the single {@link 85 * javax.inject.Provider#get()} method implemented by {@code body}. 86 */ anonymousProvider(TypeName providedType, CodeBlock body)87 public static CodeBlock anonymousProvider(TypeName providedType, CodeBlock body) { 88 return CodeBlock.of( 89 "$L", 90 anonymousClassBuilder("") 91 .superclass(daggerProviderOf(providedType)) 92 .addMethod( 93 methodBuilder("get") 94 .addAnnotation(Override.class) 95 .addModifiers(PUBLIC) 96 .returns(providedType) 97 .addCode(body) 98 .build()) 99 .build()); 100 } 101 anonymousLazy(TypeName providedType, CodeBlock body)102 public static CodeBlock anonymousLazy(TypeName providedType, CodeBlock body) { 103 return CodeBlock.of( 104 "$L", 105 anonymousClassBuilder("") 106 .superclass(lazyOf(providedType)) 107 .addMethod( 108 methodBuilder("get") 109 .addAnnotation(Override.class) 110 .addModifiers(PUBLIC) 111 .returns(providedType) 112 .addCode(body) 113 .build()) 114 .build()); 115 } 116 117 /** Returns {@code expression} cast to a type. */ cast(CodeBlock expression, ClassName castTo)118 public static CodeBlock cast(CodeBlock expression, ClassName castTo) { 119 return CodeBlock.of("($T) $L", castTo, expression); 120 } 121 122 /** Returns {@code expression} cast to a type. */ cast(CodeBlock expression, Class<?> castTo)123 public static CodeBlock cast(CodeBlock expression, Class<?> castTo) { 124 return CodeBlock.of("($T) $L", castTo, expression); 125 } 126 type(XType type)127 public static CodeBlock type(XType type) { 128 return CodeBlock.of("$T", type.getTypeName()); 129 } 130 stringLiteral(String toWrap)131 public static CodeBlock stringLiteral(String toWrap) { 132 return CodeBlock.of("$S", toWrap); 133 } 134 CodeBlocks()135 private CodeBlocks() {} 136 } 137