aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorZac Sweers <zac.sweers@gmail.com>2020-01-01 08:40:39 -0500
committerEgor Andreevich <andreevich.egor@gmail.com>2020-01-01 08:40:39 -0500
commite2ed025d5936a65836f1a6f79c750a3197f290e9 (patch)
tree7660b0963a8df363a9e252710bbcfb88687e6df9
parent4272265a319a562bceaa537fc1b9b6b40236a881 (diff)
downloadjavapoet-e2ed025d5936a65836f1a6f79c750a3197f290e9.tar.gz
Ensure trailing newlines in javadocs and method bodies (#732)
* Add RecordingAppendable in LineWrapper for tracking last emitted char * Check lastChar in javadoc emission to emit newline if necessary Resolves #731 * Move trailing newline check to emit() overload for reuse Allows using from anywhere emitting a CodeBlock * Ensure trailing newlines in method bodies Resolves #722 * Add dedicated trailing newline in javadoc test * Fix modifier ordering * Fix rebase conflict Co-authored-by: Egor Andreevich <andreevich.egor@gmail.com>
-rw-r--r--src/main/java/com/squareup/javapoet/CodeWriter.java9
-rw-r--r--src/main/java/com/squareup/javapoet/LineWrapper.java38
-rw-r--r--src/main/java/com/squareup/javapoet/MethodSpec.java2
-rw-r--r--src/test/java/com/squareup/javapoet/MethodSpecTest.java23
-rw-r--r--src/test/java/com/squareup/javapoet/TypeSpecTest.java33
5 files changed, 100 insertions, 5 deletions
diff --git a/src/main/java/com/squareup/javapoet/CodeWriter.java b/src/main/java/com/squareup/javapoet/CodeWriter.java
index b2b088b..b2bc3d3 100644
--- a/src/main/java/com/squareup/javapoet/CodeWriter.java
+++ b/src/main/java/com/squareup/javapoet/CodeWriter.java
@@ -149,7 +149,7 @@ final class CodeWriter {
emit("/**\n");
javadoc = true;
try {
- emit(javadocCodeBlock);
+ emit(javadocCodeBlock, true);
} finally {
javadoc = false;
}
@@ -219,6 +219,10 @@ final class CodeWriter {
}
public CodeWriter emit(CodeBlock codeBlock) throws IOException {
+ return emit(codeBlock, false);
+ }
+
+ public CodeWriter emit(CodeBlock codeBlock, boolean ensureTrailingNewline) throws IOException {
int a = 0;
ClassName deferredTypeName = null; // used by "import static" logic
ListIterator<String> partIterator = codeBlock.formatParts.listIterator();
@@ -307,6 +311,9 @@ final class CodeWriter {
break;
}
}
+ if (ensureTrailingNewline && out.lastChar() != '\n') {
+ emit("\n");
+ }
return this;
}
diff --git a/src/main/java/com/squareup/javapoet/LineWrapper.java b/src/main/java/com/squareup/javapoet/LineWrapper.java
index 6aa3131..928d9f4 100644
--- a/src/main/java/com/squareup/javapoet/LineWrapper.java
+++ b/src/main/java/com/squareup/javapoet/LineWrapper.java
@@ -24,7 +24,7 @@ import static com.squareup.javapoet.Util.checkNotNull;
* or soft-wrapping spaces using {@link #wrappingSpace}.
*/
final class LineWrapper {
- private final Appendable out;
+ private final RecordingAppendable out;
private final String indent;
private final int columnLimit;
private boolean closed;
@@ -47,11 +47,16 @@ final class LineWrapper {
LineWrapper(Appendable out, String indent, int columnLimit) {
checkNotNull(out, "out == null");
- this.out = out;
+ this.out = new RecordingAppendable(out);
this.indent = indent;
this.columnLimit = columnLimit;
}
+ /** @return the last emitted char or {@link Character#MIN_VALUE} if nothing emitted yet. */
+ char lastChar() {
+ return out.lastChar;
+ }
+
/** Emit {@code s}. This may be buffered to permit line wraps to be inserted. */
void append(String s) throws IOException {
if (closed) throw new IllegalStateException("closed");
@@ -134,4 +139,33 @@ final class LineWrapper {
private enum FlushType {
WRAP, SPACE, EMPTY;
}
+
+ /** A delegating {@link Appendable} that records info about the chars passing through it. */
+ static final class RecordingAppendable implements Appendable {
+ private final Appendable delegate;
+
+ char lastChar = Character.MIN_VALUE;
+
+ RecordingAppendable(Appendable delegate) {
+ this.delegate = delegate;
+ }
+
+ @Override public Appendable append(CharSequence csq) throws IOException {
+ int length = csq.length();
+ if (length != 0) {
+ lastChar = csq.charAt(length - 1);
+ }
+ return delegate.append(csq);
+ }
+
+ @Override public Appendable append(CharSequence csq, int start, int end) throws IOException {
+ CharSequence sub = csq.subSequence(start, end);
+ return append(sub);
+ }
+
+ @Override public Appendable append(char c) throws IOException {
+ lastChar = c;
+ return delegate.append(c);
+ }
+ }
}
diff --git a/src/main/java/com/squareup/javapoet/MethodSpec.java b/src/main/java/com/squareup/javapoet/MethodSpec.java
index b06290f..2f9be0e 100644
--- a/src/main/java/com/squareup/javapoet/MethodSpec.java
+++ b/src/main/java/com/squareup/javapoet/MethodSpec.java
@@ -132,7 +132,7 @@ public final class MethodSpec {
codeWriter.emit(" {\n");
codeWriter.indent();
- codeWriter.emit(code);
+ codeWriter.emit(code, true);
codeWriter.unindent();
codeWriter.emit("}\n");
diff --git a/src/test/java/com/squareup/javapoet/MethodSpecTest.java b/src/test/java/com/squareup/javapoet/MethodSpecTest.java
index 789661d..8704ec1 100644
--- a/src/test/java/com/squareup/javapoet/MethodSpecTest.java
+++ b/src/test/java/com/squareup/javapoet/MethodSpecTest.java
@@ -393,4 +393,27 @@ public final class MethodSpecTest {
builder.typeVariables.remove(1);
assertThat(builder.build().typeVariables).containsExactly(t);
}
+
+ @Test public void ensureTrailingNewline() {
+ MethodSpec methodSpec = MethodSpec.methodBuilder("method")
+ .addCode("codeWithNoNewline();")
+ .build();
+
+ assertThat(methodSpec.toString()).isEqualTo(""
+ + "void method() {\n"
+ + " codeWithNoNewline();\n"
+ + "}\n");
+ }
+
+ /** Ensures that we don't add a duplicate newline if one is already present. */
+ @Test public void ensureTrailingNewlineWithExistingNewline() {
+ MethodSpec methodSpec = MethodSpec.methodBuilder("method")
+ .addCode("codeWithNoNewline();\n") // Have a newline already, so ensure we're not adding one
+ .build();
+
+ assertThat(methodSpec.toString()).isEqualTo(""
+ + "void method() {\n"
+ + " codeWithNoNewline();\n"
+ + "}\n");
+ }
}
diff --git a/src/test/java/com/squareup/javapoet/TypeSpecTest.java b/src/test/java/com/squareup/javapoet/TypeSpecTest.java
index 6175607..f76e6f0 100644
--- a/src/test/java/com/squareup/javapoet/TypeSpecTest.java
+++ b/src/test/java/com/squareup/javapoet/TypeSpecTest.java
@@ -1852,7 +1852,8 @@ public final class TypeSpecTest {
+ " }\n"
+ "\n"
+ " /**\n"
- + " * chosen by fair dice roll ;) */\n"
+ + " * chosen by fair dice roll ;)\n"
+ + " */\n"
+ " public int getRandomQuantity() {\n"
+ " return 4;\n"
+ " }\n"
@@ -2516,4 +2517,34 @@ public final class TypeSpecTest {
builder.originatingElements.clear();
assertThat(builder.build().originatingElements).isEmpty();
}
+
+ @Test public void javadocWithTrailingLineDoesNotAddAnother() {
+ TypeSpec spec = TypeSpec.classBuilder("Taco")
+ .addJavadoc("Some doc with a newline\n")
+ .build();
+
+ assertThat(toString(spec)).isEqualTo(""
+ + "package com.squareup.tacos;\n"
+ + "\n"
+ + "/**\n"
+ + " * Some doc with a newline\n"
+ + " */\n"
+ + "class Taco {\n"
+ + "}\n");
+ }
+
+ @Test public void javadocEnsuresTrailingLine() {
+ TypeSpec spec = TypeSpec.classBuilder("Taco")
+ .addJavadoc("Some doc with a newline")
+ .build();
+
+ assertThat(toString(spec)).isEqualTo(""
+ + "package com.squareup.tacos;\n"
+ + "\n"
+ + "/**\n"
+ + " * Some doc with a newline\n"
+ + " */\n"
+ + "class Taco {\n"
+ + "}\n");
+ }
}