[jOOQ/jOOQ#10196] GeneratorWriter should auto-indent generated code

This commit is contained in:
Lukas Eder 2020-05-14 14:01:42 +02:00
parent 916fac56b6
commit 123d979ecd
4 changed files with 1178 additions and 1080 deletions

View File

@ -40,6 +40,7 @@ package org.jooq.codegen;
import static java.util.Arrays.asList;
import static java.util.Collections.unmodifiableSet;
import static org.jooq.codegen.AbstractGenerator.Language.JAVA;
import static org.jooq.codegen.AbstractGenerator.Language.KOTLIN;
import static org.jooq.codegen.AbstractGenerator.Language.SCALA;
import static org.jooq.codegen.GenerationUtil.ExpressionType.CONSTRUCTOR_REFERENCE;
import static org.jooq.codegen.GenerationUtil.ExpressionType.EXPRESSION;
@ -171,6 +172,37 @@ class GenerationUtil {
"@"*/
)));
private static Set<String> KOTLIN_KEYWORDS = unmodifiableSet(new HashSet<>(asList(
"as",
"break",
"class",
"continue",
"do",
"else",
"false",
"for",
"fun",
"if",
"in",
"interface",
"is",
"null",
"object",
"package",
"return",
"super",
"this",
"throw",
"true",
"try",
"typealias",
"typeof",
"val",
"var",
"when",
"while"
)));
private static Set<Character> SCALA_WHITESPACE = unmodifiableSet(new HashSet<>(asList(
(char)0x0020,
(char)0x0009,
@ -299,12 +331,16 @@ class GenerationUtil {
return literal + "_";
if (language == SCALA && SCALA_KEYWORDS.contains(literal))
return "`" + literal + "`";
if (language == KOTLIN && KOTLIN_KEYWORDS.contains(literal))
return "`" + literal + "`";
StringBuilder sb = new StringBuilder();
if ("".equals(literal))
if (language == SCALA)
return "`_`";
else if (language == KOTLIN)
return "`_`";
else
return "_";
@ -313,15 +349,21 @@ class GenerationUtil {
// [#5424] Scala setters, by convention, end in "property_=", where "=" is an operator and "_" precedes it
if (language == SCALA && i == literal.length() - 1 && literal.length() >= 2 && literal.charAt(i - 1) == '_' && isScalaOperator(c))
sb.append(c);
sb.append(c);
else if (language == SCALA && !isScalaIdentifierPart(c))
sb.append(escape(c));
else if (language == JAVA && !Character.isJavaIdentifierPart(c))
sb.append(escape(c));
sb.append(escape(c));
else if (language == SCALA && i == 0 && !isScalaIdentifierStart(c))
sb.append("_").append(c);
else if (language == JAVA && i == 0 && !Character.isJavaIdentifierStart(c))
sb.append("_").append(c);
// TODO: Should we do this for Scala as well?
else if (language == KOTLIN && !Character.isJavaIdentifierPart(c))
return "`" + literal + "`";
else if (language == KOTLIN && i == 0 && !Character.isJavaIdentifierStart(c))
return "`" + literal + "`";
else
sb.append(c);
}

View File

@ -148,6 +148,20 @@ public abstract class GeneratorWriter<W extends GeneratorWriter<W>> {
public W print(String string, Object... args) {
string = string.replace("\n", newlineString).replace("\t", tabString);
// [#10196] The following auto-indentation logic works well in most cases
// There are known caveats:
//
// - When formatting is done outside of the GeneratorWriter (e.g. currently
// for JPA annotations, then it may fail, e.g. by producing an indentation of -1
// - When a single line is printed in steps, and a step contains such characters,
// the character is interpreted erroneously as being semantic.
if (string.startsWith("}") || string.startsWith("]") || string.startsWith(")"))
indentTabsAllLines--;
if (indentTabsAllLines < 0 && !Boolean.getBoolean("mute-indentation-error"))
new IllegalStateException("A formatting error has been produced by https://github.com/jOOQ/jOOQ/issues/10196").printStackTrace(System.err);
int indentTabsThisLine0 = indentTabsThisLine;
if (newline && indentTabsThisLine + indentTabsAllLines > 0) {
for (int i = 0; i < indentTabsThisLine + indentTabsAllLines; i++)
sb.append(tabString);
@ -156,6 +170,11 @@ public abstract class GeneratorWriter<W extends GeneratorWriter<W>> {
indentTabsThisLine = 0;
}
if (string.endsWith("{") || string.endsWith("[") || string.endsWith("("))
indentTabsAllLines++;
else if (string.startsWith("if") || string.startsWith("else") || string.startsWith("for") || string.startsWith("while"))
indentTabsThisLine = indentTabsThisLine0 + 1;
if (args.length > 0) {
List<Object> originals = Arrays.asList(args);
List<Object> translated = new ArrayList<>();

File diff suppressed because it is too large Load Diff

View File

@ -80,8 +80,7 @@ public class JavaWriter extends GeneratorWriter<JavaWriter> {
}
public JavaWriter javadoc(String string, Object... args) {
int t = tab();
tab(t).println();
println();
if (javadoc) {
@ -92,9 +91,9 @@ public class JavaWriter extends GeneratorWriter<JavaWriter> {
if (escapedArgs[i] instanceof String)
escapedArgs[i] = escapeJavadoc((String) escapedArgs[i]);
tab(t).println("/**");
tab(t).println(" * " + escaped, escapedArgs);
tab(t).println(" */");
println("/**");
println(" * " + escaped, escapedArgs);
println(" */");
}
return this;
@ -112,12 +111,10 @@ public class JavaWriter extends GeneratorWriter<JavaWriter> {
}
public JavaWriter header(String header, Object... args) {
int t = tab();
tab(t).println();
tab(t).println("// -------------------------------------------------------------------------");
tab(t).println("// " + header, args);
tab(t).println("// -------------------------------------------------------------------------");
println();
println("// -------------------------------------------------------------------------");
println("// " + header, args);
println("// -------------------------------------------------------------------------");
return this;
}
@ -135,18 +132,15 @@ public class JavaWriter extends GeneratorWriter<JavaWriter> {
}
public JavaWriter overrideInherit() {
final int t = tab();
tab(t).println();
tab(t).override();
println();
override();
return this;
}
public JavaWriter overrideInheritIf(boolean override) {
final int t = tab();
tab(t).println();
println();
if (override)
tab(t).override();
override();
return this;
}
@ -154,7 +148,7 @@ public class JavaWriter extends GeneratorWriter<JavaWriter> {
public void printSerial() {
if (isJava) {
println();
println("\tprivate static final long serialVersionUID = %s;", SERIAL_STATEMENT);
println("private static final long serialVersionUID = %s;", SERIAL_STATEMENT);
}
}
@ -236,8 +230,7 @@ public class JavaWriter extends GeneratorWriter<JavaWriter> {
// Skip unqualified and primitive types
if (c.contains(".")) {
if (isKotlin && Integer.class.getName().equals(c))
c = "kotlin.Int";
c = patchKotlinClasses(c);
// com.example.Table.TABLE.COLUMN (with keepSegments = 3)
if (fullyQualifiedTypes == null || !fullyQualifiedTypes.matcher(c).matches()) {
@ -283,4 +276,17 @@ public class JavaWriter extends GeneratorWriter<JavaWriter> {
return result;
}
private String patchKotlinClasses(String c) {
if (isKotlin) {
if (c.endsWith("[]"))
c = "kotlin.Array<" + patchKotlinClasses(c.substring(0, c.length() - 2)) + "?>";
else if (Integer.class.getName().equals(c))
c = "kotlin.Int";
else if (Object.class.getName().equals(c))
c = "kotlin.Any";
}
return c;
}
}