From 27f5b8487161c28272aed25ddfcfd75c10254f47 Mon Sep 17 00:00:00 2001 From: HliasMpGH Date: Sat, 13 Apr 2024 15:22:42 +0300 Subject: [PATCH 1/3] add lambda creation feature feature used to structure anonymous functions with CodeBlock and within MethodSpec --- .../java/com/squareup/javapoet/CodeBlock.java | 121 ++++++++++++++++++ .../com/squareup/javapoet/MethodSpec.java | 110 +++++++++++++++- .../com/squareup/javapoet/MethodSpecTest.java | 90 ++++++++++++- 3 files changed, 315 insertions(+), 6 deletions(-) diff --git a/src/main/java/com/squareup/javapoet/CodeBlock.java b/src/main/java/com/squareup/javapoet/CodeBlock.java index 5376984..1f4bcb2 100644 --- a/src/main/java/com/squareup/javapoet/CodeBlock.java +++ b/src/main/java/com/squareup/javapoet/CodeBlock.java @@ -21,11 +21,14 @@ import java.io.IOException; import java.lang.reflect.Type; import java.util.ArrayList; +import java.util.Collections; import java.util.List; import java.util.Map; import java.util.regex.Matcher; import java.util.regex.Pattern; import java.util.stream.Collector; +import java.util.stream.Collectors; +import java.util.stream.Stream; import java.util.stream.StreamSupport; import static com.squareup.javapoet.Util.checkArgument; @@ -415,6 +418,124 @@ public Builder add(CodeBlock codeBlock) { return this; } + /** + * Structures a lambda function based on some inputs and a CodeBlock body.
+ * Should be used with {@link #add(String, Object...) addCode}, + * to provide specific behaviour such as + * methodcall((int x, int y) -> x + y, 5). + * @param parameters the input parameters of the function. + * @param emitTypes true if the types of the inputs should + * be emitted on the result. + * @param body the body of the function. + */ + public Builder addLambda(Iterable parameters, boolean emitTypes, CodeBlock body) { + Stream parameterStream = StreamSupport.stream( + parameters.spliterator(), + false + ); + + // the inputs of the lambda (left side) + String inputSide = parameterStream + .peek(p -> checkArgument(!p.type.equals(TypeName.VOID), // validate the input types + "lambda input parameters cannot be of void type") + ) + .map(p -> emitTypes ? p.toString() : p.name) + .collect(Collectors.joining(", ")); + + // the count of given inputs + int paramsLen = inputSide.split(",").length; + + // on 0 or more than 1 inputs, or in case of type emission, + // parentheses are mandatory + if (paramsLen > 1 || emitTypes || inputSide.isEmpty()) { + inputSide = "(" + inputSide + ")"; + } + + // the body of the lambda (right side) + String bodySide = body.toString().replaceAll("\n", ""); + + // in case of multiple statements, braces are mandatory + if (bodySide.contains(";")) { + bodySide = "{" + bodySide + "}"; + } + + // the full lambda structure + add(inputSide + " -> " + bodySide); + return this; + } + + /** + * Structures a lambda function based on some inputs and a CodeBlock body.
+ * Will not emit the input types.
+ * Should be used with {@link #add(String, Object...) addCode}, + * to provide specific behaviour such as + * methodcall((x, y) -> x + y, 5). + * @param parameters the input parameters of the function. + * @param body the body of the function. + */ + public Builder addLambda(Iterable parameters, CodeBlock body) { + return addLambda(parameters, false, body); + } + + /** + * Structures a lambda function based on some inputs and an expression body.
+ * Should be used with {@link #add(String, Object...) addCode}, + * to provide specific behaviour such as + * methodcall((int x, int y) -> x + y, 5). + * @param parameters the input parameters of the function. + * @param emitTypes true if the types of the inputs should + * be emitted on the result. + * @param expressionFormat the format that should be used + * for the expression. + * @param args the values that should be placed in the holders + * of the format. + */ + public Builder addLambda(Iterable parameters, boolean emitTypes, + String expressionFormat, Object... args) { + return addLambda(parameters, emitTypes, CodeBlock.of(expressionFormat, args)); + } + + /** + * Structures a lambda function based on some inputs and an expression body.
+ * Will not emit the input types.
+ * Should be used with {@link #add(String, Object...) addCode}, + * to provide specific behaviour such as + * methodcall((x, y) -> x + y, 5). + * @param parameters the input parameters of the function. + * @param expressionFormat the format that should be used + * for the expression. + * @param args the values that should be placed in the holders + * of the format. + */ + public Builder addLambda(Iterable parameters, String expressionFormat, Object... args) { + return addLambda(parameters, false, CodeBlock.of(expressionFormat, args)); + } + + /** + * Structures a producer lambda function based on a CodeBlock body.
+ * Should be used with {@link #add(String, Object...) addCode}, + * to provide specific behaviour such as + * methodcall(() -> 3 + 2, 5). + * @param body the body of the lambda. + */ + public Builder addLambda(CodeBlock body) { + return addLambda(Collections.emptyList(), false, body); + } + + /** + * Structures a producer lambda function based on an expression body.
+ * Should be used with {@link #add(String, Object...) addCode}, + * to provide specific behaviour such as + * methodcall(() -> 3 + 2, 5). + * @param expressionFormat the format that should be used + * for the expression. + * @param args the values that should be placed in the holders + * of the format. + */ + public Builder addLambda(String expressionFormat, Object... args) { + return addLambda(Collections.emptyList(), false, expressionFormat, args); + } + public Builder indent() { this.formatParts.add("$>"); return this; diff --git a/src/main/java/com/squareup/javapoet/MethodSpec.java b/src/main/java/com/squareup/javapoet/MethodSpec.java index 6914858..a738a9a 100644 --- a/src/main/java/com/squareup/javapoet/MethodSpec.java +++ b/src/main/java/com/squareup/javapoet/MethodSpec.java @@ -296,21 +296,25 @@ public static final class Builder { private String name; private final CodeBlock.Builder javadoc = CodeBlock.builder(); + public final List annotations = new ArrayList<>(); + public final List modifiers = new ArrayList<>(); + public final List typeVariables = new ArrayList<>(); private TypeName returnType; + public final List parameters = new ArrayList<>(); + private boolean varargs; private final Set exceptions = new LinkedHashSet<>(); private final CodeBlock.Builder code = CodeBlock.builder(); - private boolean varargs; private CodeBlock defaultValue; - public final List typeVariables = new ArrayList<>(); - public final List annotations = new ArrayList<>(); - public final List modifiers = new ArrayList<>(); - public final List parameters = new ArrayList<>(); private Builder(String name) { setName(name); } + /** + * Sets a name for this builder. + * @param name the name to be set for the method. + */ public Builder setName(String name) { checkNotNull(name, "name == null"); checkArgument(name.equals(CONSTRUCTOR) || SourceVersion.isName(name), @@ -500,6 +504,10 @@ public Builder nextControlFlow(CodeBlock codeBlock) { return nextControlFlow("$L", codeBlock); } + /** + * Ends the last open control flow. + * Should be used once for every control flow. + */ public Builder endControlFlow() { code.endControlFlow(); return this; @@ -532,6 +540,98 @@ public Builder addStatement(CodeBlock codeBlock) { return this; } + /** + * Structures a lambda function based on some inputs and a CodeBlock body.
+ * Should be used with {@link #addCode(String, Object...) addCode}, + * to provide specific behaviour such as + * methodcall((int x, int y) -> x + y, 5). + * @param parameters the input parameters of the function. + * @param emitTypes true if the types of the inputs should + * be emitted on the result. + * @param body the body of the function. + */ + public Builder addLambda(Iterable parameters, boolean emitTypes, CodeBlock body) { + code.addLambda(parameters, emitTypes, body); + return this; + } + + /** + * Structures a lambda function based on some inputs and a CodeBlock body.
+ * Will not emit the input types.
+ * Should be used with {@link #addCode(String, Object...) addCode}, + * to provide specific behaviour such as + * methodcall((x, y) -> x + y, 5). + * @param parameters the input parameters of the function. + * @param body the body of the function. + */ + public Builder addLambda(Iterable parameters, CodeBlock body) { + code.addLambda(parameters, false, body); + return this; + } + + /** + * Structures a lambda function based on some inputs and an expression body.
+ * Should be used with {@link #addCode(String, Object...) addCode}, + * to provide specific behaviour such as + * methodcall((int x, int y) -> x + y, 5). + * @param parameters the input parameters of the function. + * @param emitTypes true if the types of the inputs should + * be emitted on the result. + * @param expressionFormat the format that should be used + * for the expression. + * @param args the values that should be placed in the holders + * of the format. + */ + public Builder addLambda(Iterable parameters, boolean emitTypes, + String expressionFormat, Object... args) { + code.addLambda(parameters, emitTypes, CodeBlock.of(expressionFormat, args)); + return this; + } + + /** + * Structures a lambda function based on some inputs and an expression body.
+ * Will not emit the input types.
+ * Should be used with {@link #addCode(String, Object...) addCode}, + * to provide specific behaviour such as + * methodcall((x, y) -> x + y, 5). + * @param parameters the input parameters of the function. + * @param expressionFormat the format that should be used + * for the expression. + * @param args the values that should be placed in the holders + * of the format. + */ + public Builder addLambda(Iterable parameters, String expressionFormat, Object... args) { + code.addLambda(parameters, false, CodeBlock.of(expressionFormat, args)); + return this; + } + + /** + * Structures a producer lambda function based on a CodeBlock body.
+ * Should be used with {@link #addCode(String, Object...) addCode}, + * to provide specific behaviour such as + * methodcall(() -> 3 + 2, 5). + * @param body the body of the lambda. + */ + public Builder addLambda(CodeBlock body) { + code.addLambda(Collections.emptyList(), false, body); + return this; + } + + /** + * Structures a producer lambda function based on an expression body.
+ * Should be used with {@link #addCode(String, Object...) addCode}, + * to provide specific behaviour such as + * methodcall(() -> 3 + 2, 5). + * @param expressionFormat the format that should be used + * for the expression. + * @param args the values that should be placed in the holders + * of the format. + */ + public Builder addLambda(String expressionFormat, Object... args) { + code.addLambda(Collections.emptyList(), false, expressionFormat, args); + return this; + } + public MethodSpec build() { return new MethodSpec(this); } diff --git a/src/test/java/com/squareup/javapoet/MethodSpecTest.java b/src/test/java/com/squareup/javapoet/MethodSpecTest.java index 56cc3b7..7611eb4 100644 --- a/src/test/java/com/squareup/javapoet/MethodSpecTest.java +++ b/src/test/java/com/squareup/javapoet/MethodSpecTest.java @@ -482,8 +482,96 @@ abstract static class AbstractClassWithPrivateAnnotation { "}\n"); } - private static CodeBlock named(String format, Map args){ + private static CodeBlock named(String format, Map args) { return CodeBlock.builder().addNamed(format, args).build(); } + @Test public void ensureLambdaTypeError() { + // parameter with void type - should be rejected + ParameterSpec p1 = ParameterSpec.builder(TypeName.VOID, "x").build(); + + try { + // check that void type will cause errors + CodeBlock.builder() + .addLambda(List.of(p1), "$N * 2", "x"); + + fail(); + } catch (IllegalArgumentException expected) { + assertThat(expected).hasMessageThat().isEqualTo( + "lambda input parameters cannot be of void type" + ); + } + } + + @Test public void ensureLambdaMethodSpecLiability() { + // lambda inputs + ParameterSpec p1 = ParameterSpec.builder(TypeName.INT, "x").build(); + ParameterSpec p2 = ParameterSpec.builder(TypeName.DOUBLE, "y").build(); + + // lambda body that considers input values + CodeBlock body1 = CodeBlock.of("int $3N = 3; return $1N + $2N + $3N;", "x", "y", "z"); + + // lambda body that does not consider input values + CodeBlock body2 = CodeBlock.of("int $1N = 3; int $2N = 5; return $1N + $2N;", "x", "y"); + + MethodSpec method = MethodSpec.methodBuilder("method") + .addCode("methodCall(") + .addLambda(List.of(p1, p2), true, body1) // lambda with multiple inputs and (CodeBlock) body + .addCode(", ") + .addLambda(List.of(p2), + "$N + $N", "x", "y") // lambda with single input and (String) body + .addCode(", ") + .addLambda(body2) // lambda with no inputs and (CodeBlock) body + .addCode(", ") + .addLambda("5 + 7") // lambda with no inputs and (String) body + .addCode(", ") + .addLambda("method1(); method2();") // lambda with multiple statements + .addCode(", ") + .addLambda(List.of(p1), true, "x + 5") // lambda with single input of emitted type + .addCode(");\n") + .build(); + + assertThat(method.toString()).isEqualTo( + "void method() {\n" + + " methodCall(" + + "(int x, double y) -> {int z = 3; return x + y + z;}, " + + "y -> x + y, " + + "() -> {int x = 3; int y = 5; return x + y;}, " + + "() -> 5 + 7, " + + "() -> {method1(); method2();}, " + + "(int x) -> x + 5" + + ");\n" + + "}\n" + ); + } + + @Test public void ensureLambdaCodeBlockLiability() { + // lambda body that does not consider input values + CodeBlock body = CodeBlock.of("int $1N = 3; int $2N = 5; return $1N + $2N;", "x", "y"); + + // lambda expression that does not consider input values + CodeBlock body2 = CodeBlock.of("5 + 3"); + + CodeBlock codeWithLambda = CodeBlock.builder() + .add("methodCall(") + .addLambda(body) // producer lambda + .add(", ") + .addLambda(body2) + .add(");") + .build(); + + MethodSpec method = MethodSpec.methodBuilder("method") + .addCode(codeWithLambda) + .build(); + + assertThat(method.toString()).isEqualTo( + "void method() {\n" + + " methodCall(" + + "() -> {int x = 3; int y = 5; return x + y;}, " + + "() -> 5 + 3" + + ");\n" + + "}\n" + ); + } + } From 900d01a4a55389caca1b11d291ffc31392f64533 Mon Sep 17 00:00:00 2001 From: HliasMpGH Date: Thu, 30 May 2024 02:46:24 +0300 Subject: [PATCH 2/3] add enum to manage different types of lambda modes; update addLambda methods --- .../java/com/squareup/javapoet/CodeBlock.java | 54 +++++++++++++++---- .../com/squareup/javapoet/LambdaMode.java | 11 ++++ .../com/squareup/javapoet/MethodSpec.java | 54 +++++++++++++++---- .../com/squareup/javapoet/MethodSpecTest.java | 4 +- 4 files changed, 99 insertions(+), 24 deletions(-) create mode 100644 src/main/java/com/squareup/javapoet/LambdaMode.java diff --git a/src/main/java/com/squareup/javapoet/CodeBlock.java b/src/main/java/com/squareup/javapoet/CodeBlock.java index 1f4bcb2..ebedbd6 100644 --- a/src/main/java/com/squareup/javapoet/CodeBlock.java +++ b/src/main/java/com/squareup/javapoet/CodeBlock.java @@ -424,11 +424,14 @@ public Builder add(CodeBlock codeBlock) { * to provide specific behaviour such as * methodcall((int x, int y) -> x + y, 5). * @param parameters the input parameters of the function. - * @param emitTypes true if the types of the inputs should - * be emitted on the result. + * @param mode the format mode that should be used. + * @see com.squareup.javapoet.LambdaMode LambdaMode. * @param body the body of the function. */ - public Builder addLambda(Iterable parameters, boolean emitTypes, CodeBlock body) { + public Builder addLambda(Iterable parameters, LambdaMode mode, CodeBlock body) { + // check for specification of input type visibility + boolean emitTypes = mode.equals(LambdaMode.VISIBLE_TYPES); + Stream parameterStream = StreamSupport.stream( parameters.spliterator(), false @@ -474,7 +477,7 @@ public Builder addLambda(Iterable parameters, boolean emitTypes, * @param body the body of the function. */ public Builder addLambda(Iterable parameters, CodeBlock body) { - return addLambda(parameters, false, body); + return addLambda(parameters, LambdaMode.DEFAULT, body); } /** @@ -483,16 +486,16 @@ public Builder addLambda(Iterable parameters, CodeBlock body) { * to provide specific behaviour such as * methodcall((int x, int y) -> x + y, 5). * @param parameters the input parameters of the function. - * @param emitTypes true if the types of the inputs should - * be emitted on the result. + * @param mode the format mode that should be used. + * @see com.squareup.javapoet.LambdaMode LambdaMode. * @param expressionFormat the format that should be used * for the expression. * @param args the values that should be placed in the holders * of the format. */ - public Builder addLambda(Iterable parameters, boolean emitTypes, + public Builder addLambda(Iterable parameters, LambdaMode mode, String expressionFormat, Object... args) { - return addLambda(parameters, emitTypes, CodeBlock.of(expressionFormat, args)); + return addLambda(parameters, mode, CodeBlock.of(expressionFormat, args)); } /** @@ -508,7 +511,20 @@ public Builder addLambda(Iterable parameters, boolean emitTypes, * of the format. */ public Builder addLambda(Iterable parameters, String expressionFormat, Object... args) { - return addLambda(parameters, false, CodeBlock.of(expressionFormat, args)); + return addLambda(parameters, LambdaMode.DEFAULT, CodeBlock.of(expressionFormat, args)); + } + + /** + * Structures a producer lambda function based on a CodeBlock body.
+ * Should be used with {@link #addCode(String, Object...) addCode}, + * to provide specific behaviour such as + * methodcall(() -> 3 + 2, 5). + * @param mode the format mode that should be used. + * @see com.squareup.javapoet.LambdaMode LambdaMode. + * @param body the body of the lambda. + */ + public Builder addLambda(LambdaMode mode, CodeBlock body) { + return addLambda(Collections.emptyList(), mode, body); } /** @@ -519,7 +535,23 @@ public Builder addLambda(Iterable parameters, String expressionFo * @param body the body of the lambda. */ public Builder addLambda(CodeBlock body) { - return addLambda(Collections.emptyList(), false, body); + return addLambda(Collections.emptyList(), LambdaMode.DEFAULT, body); + } + + /** + * Structures a producer lambda function based on an expression body.
+ * Should be used with {@link #addCode(String, Object...) addCode}, + * to provide specific behaviour such as + * methodcall(() -> 3 + 2, 5). + * @param mode the format mode that should be used. + * @see com.squareup.javapoet.LambdaMode LambdaMode. + * @param expressionFormat the format that should be used + * for the expression. + * @param args the values that should be placed in the holders + * of the format. + */ + public Builder addLambda(LambdaMode mode, String expressionFormat, Object... args) { + return addLambda(Collections.emptyList(), mode, expressionFormat, args); } /** @@ -533,7 +565,7 @@ public Builder addLambda(CodeBlock body) { * of the format. */ public Builder addLambda(String expressionFormat, Object... args) { - return addLambda(Collections.emptyList(), false, expressionFormat, args); + return addLambda(Collections.emptyList(), LambdaMode.DEFAULT, expressionFormat, args); } public Builder indent() { diff --git a/src/main/java/com/squareup/javapoet/LambdaMode.java b/src/main/java/com/squareup/javapoet/LambdaMode.java new file mode 100644 index 0000000..503101b --- /dev/null +++ b/src/main/java/com/squareup/javapoet/LambdaMode.java @@ -0,0 +1,11 @@ +package com.squareup.javapoet; + +/** + * The available format modes a lambda function can have. + * {@code DEFAULT} example: (x, y) -> x + y; + * {@code VISIBLE_TYPES} example: (int x, int y) -> x + y; +*/ +public enum LambdaMode { + DEFAULT, + VISIBLE_TYPES +} diff --git a/src/main/java/com/squareup/javapoet/MethodSpec.java b/src/main/java/com/squareup/javapoet/MethodSpec.java index a738a9a..e258326 100644 --- a/src/main/java/com/squareup/javapoet/MethodSpec.java +++ b/src/main/java/com/squareup/javapoet/MethodSpec.java @@ -546,12 +546,13 @@ public Builder addStatement(CodeBlock codeBlock) { * to provide specific behaviour such as * methodcall((int x, int y) -> x + y, 5). * @param parameters the input parameters of the function. - * @param emitTypes true if the types of the inputs should + * @param mode the format mode that should be used. + * @see com.squareup.javapoet.LambdaMode LambdaMode. * be emitted on the result. * @param body the body of the function. */ - public Builder addLambda(Iterable parameters, boolean emitTypes, CodeBlock body) { - code.addLambda(parameters, emitTypes, body); + public Builder addLambda(Iterable parameters, LambdaMode mode, CodeBlock body) { + code.addLambda(parameters, mode, body); return this; } @@ -565,7 +566,7 @@ public Builder addLambda(Iterable parameters, boolean emitTypes, * @param body the body of the function. */ public Builder addLambda(Iterable parameters, CodeBlock body) { - code.addLambda(parameters, false, body); + code.addLambda(parameters, LambdaMode.DEFAULT, body); return this; } @@ -575,16 +576,16 @@ public Builder addLambda(Iterable parameters, CodeBlock body) { * to provide specific behaviour such as * methodcall((int x, int y) -> x + y, 5). * @param parameters the input parameters of the function. - * @param emitTypes true if the types of the inputs should - * be emitted on the result. + * @param mode the format mode that should be used. + * @see com.squareup.javapoet.LambdaMode LambdaMode. * @param expressionFormat the format that should be used * for the expression. * @param args the values that should be placed in the holders * of the format. */ - public Builder addLambda(Iterable parameters, boolean emitTypes, + public Builder addLambda(Iterable parameters, LambdaMode mode, String expressionFormat, Object... args) { - code.addLambda(parameters, emitTypes, CodeBlock.of(expressionFormat, args)); + code.addLambda(parameters, mode, CodeBlock.of(expressionFormat, args)); return this; } @@ -601,7 +602,21 @@ public Builder addLambda(Iterable parameters, boolean emitTypes, * of the format. */ public Builder addLambda(Iterable parameters, String expressionFormat, Object... args) { - code.addLambda(parameters, false, CodeBlock.of(expressionFormat, args)); + code.addLambda(parameters, LambdaMode.DEFAULT, CodeBlock.of(expressionFormat, args)); + return this; + } + + /** + * Structures a producer lambda function based on a CodeBlock body.
+ * Should be used with {@link #addCode(String, Object...) addCode}, + * to provide specific behaviour such as + * methodcall(() -> 3 + 2, 5). + * @param mode the format mode that should be used. + * @see com.squareup.javapoet.LambdaMode LambdaMode. + * @param body the body of the lambda. + */ + public Builder addLambda(LambdaMode mode, CodeBlock body) { + code.addLambda(Collections.emptyList(), mode, body); return this; } @@ -613,7 +628,24 @@ public Builder addLambda(Iterable parameters, String expressionFo * @param body the body of the lambda. */ public Builder addLambda(CodeBlock body) { - code.addLambda(Collections.emptyList(), false, body); + code.addLambda(Collections.emptyList(), LambdaMode.DEFAULT, body); + return this; + } + + /** + * Structures a producer lambda function based on an expression body.
+ * Should be used with {@link #addCode(String, Object...) addCode}, + * to provide specific behaviour such as + * methodcall(() -> 3 + 2, 5). + * @param mode the format mode that should be used. + * @see com.squareup.javapoet.LambdaMode LambdaMode. + * @param expressionFormat the format that should be used + * for the expression. + * @param args the values that should be placed in the holders + * of the format. + */ + public Builder addLambda(LambdaMode mode, String expressionFormat, Object... args) { + code.addLambda(Collections.emptyList(), mode, expressionFormat, args); return this; } @@ -628,7 +660,7 @@ public Builder addLambda(CodeBlock body) { * of the format. */ public Builder addLambda(String expressionFormat, Object... args) { - code.addLambda(Collections.emptyList(), false, expressionFormat, args); + code.addLambda(Collections.emptyList(), LambdaMode.DEFAULT, expressionFormat, args); return this; } diff --git a/src/test/java/com/squareup/javapoet/MethodSpecTest.java b/src/test/java/com/squareup/javapoet/MethodSpecTest.java index 7611eb4..75fa04a 100644 --- a/src/test/java/com/squareup/javapoet/MethodSpecTest.java +++ b/src/test/java/com/squareup/javapoet/MethodSpecTest.java @@ -516,7 +516,7 @@ private static CodeBlock named(String format, Map args) { MethodSpec method = MethodSpec.methodBuilder("method") .addCode("methodCall(") - .addLambda(List.of(p1, p2), true, body1) // lambda with multiple inputs and (CodeBlock) body + .addLambda(List.of(p1, p2), LambdaMode.VISIBLE_TYPES, body1) // lambda with multiple inputs and (CodeBlock) body .addCode(", ") .addLambda(List.of(p2), "$N + $N", "x", "y") // lambda with single input and (String) body @@ -527,7 +527,7 @@ private static CodeBlock named(String format, Map args) { .addCode(", ") .addLambda("method1(); method2();") // lambda with multiple statements .addCode(", ") - .addLambda(List.of(p1), true, "x + 5") // lambda with single input of emitted type + .addLambda(List.of(p1), LambdaMode.VISIBLE_TYPES, "x + 5") // lambda with single input of emitted type .addCode(");\n") .build(); From 16fd07ce79c96cf5a719ebbaa8304054ab1d36d0 Mon Sep 17 00:00:00 2001 From: HliasMpGH Date: Thu, 30 May 2024 03:02:26 +0300 Subject: [PATCH 3/3] add test to ensure nothing breaks when redundant modes are specifed on lambda --- .../com/squareup/javapoet/MethodSpecTest.java | 27 +++++++++++++++++++ 1 file changed, 27 insertions(+) diff --git a/src/test/java/com/squareup/javapoet/MethodSpecTest.java b/src/test/java/com/squareup/javapoet/MethodSpecTest.java index 75fa04a..50eb992 100644 --- a/src/test/java/com/squareup/javapoet/MethodSpecTest.java +++ b/src/test/java/com/squareup/javapoet/MethodSpecTest.java @@ -574,4 +574,31 @@ private static CodeBlock named(String format, Map args) { ); } + @Test public void ensureLambdaModeLiability() { + // lambda body that does not consider input values + CodeBlock body = CodeBlock.of("int $1N = 3; int $2N = 5; return $1N + $2N;", "x", "y"); + + CodeBlock codeWithLambda = CodeBlock.builder() + .add("methodCall(") + .addLambda(LambdaMode.VISIBLE_TYPES, "5 + 3") // ensure that redundant mode specification doesnt break anything + .add(");\n") + .build(); + + MethodSpec method = MethodSpec.methodBuilder("method") + .addCode(codeWithLambda) + .addCode("Producer x = ") + .addLambda(LambdaMode.VISIBLE_TYPES, body) // ensure that redundant mode specification doesnt break anything + .addCode(";") + .build(); + + assertThat(method.toString()).isEqualTo( + "void method() {\n" + + " methodCall(" + + "() -> 5 + 3" + + ");\n" + + " Producer x = () -> {int x = 3; int y = 5; return x + y;};\n" + + "}\n" + ); + } + }