Major update for pretty print, adding interfaces for printer configuration, printer, ... and deprecated old PrettyPrinter API
diff --git a/javaparser-core-metamodel-generator/src/main/java/com/github/javaparser/generator/metamodel/MetaModelGenerator.java b/javaparser-core-metamodel-generator/src/main/java/com/github/javaparser/generator/metamodel/MetaModelGenerator.java
index ea9ad4a..cc63ba4 100644
--- a/javaparser-core-metamodel-generator/src/main/java/com/github/javaparser/generator/metamodel/MetaModelGenerator.java
+++ b/javaparser-core-metamodel-generator/src/main/java/com/github/javaparser/generator/metamodel/MetaModelGenerator.java
@@ -21,6 +21,15 @@
package com.github.javaparser.generator.metamodel;
+import static com.github.javaparser.utils.Utils.decapitalize;
+
+import java.lang.reflect.Field;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.util.ArrayList;
+import java.util.Comparator;
+import java.util.List;
+
import com.github.javaparser.ParserConfiguration;
import com.github.javaparser.StaticJavaParser;
import com.github.javaparser.ast.CompilationUnit;
@@ -30,19 +39,13 @@
import com.github.javaparser.ast.body.MethodDeclaration;
import com.github.javaparser.ast.stmt.Statement;
import com.github.javaparser.generator.AbstractGenerator;
-import com.github.javaparser.printer.PrettyPrinter;
-import com.github.javaparser.printer.PrettyPrinterConfiguration;
+import com.github.javaparser.printer.PrettyPrintable;
+import com.github.javaparser.printer.Printable;
+import com.github.javaparser.printer.configuration.ConfigurablePrinter;
+import com.github.javaparser.printer.configuration.PrinterConfiguration;
+import com.github.javaparser.printer.configuration.PrinterConfiguration.ConfigOption;
import com.github.javaparser.utils.SourceRoot;
-import java.lang.reflect.Field;
-import java.nio.file.Path;
-import java.nio.file.Paths;
-import java.util.ArrayList;
-import java.util.Comparator;
-import java.util.List;
-
-import static com.github.javaparser.utils.Utils.decapitalize;
-
public class MetaModelGenerator extends AbstractGenerator {
static final String BASE_NODE_META_MODEL = "BaseNodeMetaModel";
@@ -196,7 +199,9 @@
.setLanguageLevel(ParserConfiguration.LanguageLevel.RAW)
.setStoreTokens(false);
final SourceRoot sourceRoot = new SourceRoot(root, parserConfiguration);
- sourceRoot.setPrinter(new PrettyPrinter(new PrettyPrinterConfiguration().setEndOfLineCharacter("\n"))::print);
+ ConfigurablePrinter config = new PrinterConfiguration().addOption(ConfigOption.END_OF_LINE_CHARACTER.value("\n");
+ Printable printer = new PrettyPrintable(config);
+ sourceRoot.setPrinter(printer::print);
StaticJavaParser.setConfiguration(parserConfiguration);
new MetaModelGenerator(sourceRoot).generate();
diff --git a/javaparser-core-testing-bdd/src/test/java/com/github/javaparser/steps/CommentParsingSteps.java b/javaparser-core-testing-bdd/src/test/java/com/github/javaparser/steps/CommentParsingSteps.java
index 6c6a623..664efd9 100644
--- a/javaparser-core-testing-bdd/src/test/java/com/github/javaparser/steps/CommentParsingSteps.java
+++ b/javaparser-core-testing-bdd/src/test/java/com/github/javaparser/steps/CommentParsingSteps.java
@@ -31,8 +31,8 @@
import com.github.javaparser.ast.stmt.ExpressionStmt;
import com.github.javaparser.ast.type.PrimitiveType;
import com.github.javaparser.printer.PrettyPrinter;
-import com.github.javaparser.printer.PrettyPrinterConfiguration;
import com.github.javaparser.printer.Printable;
+import com.github.javaparser.printer.configuration.PrettyPrinterConfiguration;
import org.jbehave.core.annotations.Alias;
import org.jbehave.core.annotations.Given;
diff --git a/javaparser-core-testing/src/test/java/com/github/javaparser/ast/comments/CommentTest.java b/javaparser-core-testing/src/test/java/com/github/javaparser/ast/comments/CommentTest.java
index 7ae834a..8892e02 100644
--- a/javaparser-core-testing/src/test/java/com/github/javaparser/ast/comments/CommentTest.java
+++ b/javaparser-core-testing/src/test/java/com/github/javaparser/ast/comments/CommentTest.java
@@ -21,23 +21,29 @@
package com.github.javaparser.ast.comments;
+import static com.github.javaparser.StaticJavaParser.parse;
+import static com.github.javaparser.utils.TestUtils.assertEqualsStringIgnoringEol;
+import static com.github.javaparser.utils.Utils.SYSTEM_EOL;
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertFalse;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+
+import org.junit.jupiter.api.Test;
+
import com.github.javaparser.ast.CompilationUnit;
import com.github.javaparser.ast.NodeList;
import com.github.javaparser.ast.body.ClassOrInterfaceDeclaration;
import com.github.javaparser.ast.body.MethodDeclaration;
import com.github.javaparser.javadoc.Javadoc;
import com.github.javaparser.javadoc.description.JavadocDescription;
-import com.github.javaparser.printer.PrettyPrinterConfiguration;
-import org.junit.jupiter.api.Test;
-
-import static com.github.javaparser.StaticJavaParser.parse;
-import static com.github.javaparser.utils.TestUtils.assertEqualsStringIgnoringEol;
-import static com.github.javaparser.utils.Utils.SYSTEM_EOL;
-import static org.junit.jupiter.api.Assertions.*;
+import com.github.javaparser.printer.configuration.ConfigurablePrinter;
+import com.github.javaparser.printer.configuration.Indentation;
+import com.github.javaparser.printer.configuration.Indentation.IndentType;
+import com.github.javaparser.printer.configuration.PrinterConfiguration;
class CommentTest {
- private static final PrettyPrinterConfiguration PRETTY_PRINTER_CONFIG_TWO_INDENT = new PrettyPrinterConfiguration().setIndentSize(2);
+ private static final ConfigurablePrinter PRETTY_PRINTER_CONFIG_TWO_INDENT = new PrinterConfiguration().setIndentation(new Indentation(IndentType.SPACES, 2));
@Test
void removeOrphanComment() {
diff --git a/javaparser-core-testing/src/test/java/com/github/javaparser/printer/PrettyPrintVisitorTest.java b/javaparser-core-testing/src/test/java/com/github/javaparser/printer/PrettyPrintVisitorTest.java
index d688aed..cefd5ca 100644
--- a/javaparser-core-testing/src/test/java/com/github/javaparser/printer/PrettyPrintVisitorTest.java
+++ b/javaparser-core-testing/src/test/java/com/github/javaparser/printer/PrettyPrintVisitorTest.java
@@ -43,6 +43,9 @@
import com.github.javaparser.ast.expr.VariableDeclarationExpr;
import com.github.javaparser.ast.stmt.Statement;
import com.github.javaparser.ast.type.Type;
+import com.github.javaparser.printer.configuration.ConfigurablePrinter;
+import com.github.javaparser.printer.configuration.PrinterConfiguration;
+import com.github.javaparser.printer.configuration.PrinterConfiguration.ConfigOption;
class PrettyPrintVisitorTest {
@@ -68,11 +71,11 @@
}
private String print(Node node) {
- return new PrettyPrinter().print(node);
+ return new PrettyPrintable().print(node);
}
- private String print(Node node, PrettyPrinterConfiguration conf) {
- return new PrettyPrinter(conf).print(node);
+ private String print(Node node, ConfigurablePrinter conf) {
+ return new PrettyPrintable(conf).print(node);
}
@@ -88,7 +91,7 @@
*/
@Test
void printOperatorsR0(){
- PrettyPrinterConfiguration conf1 = new PrettyPrinterConfiguration().setSpaceAroundOperators(false);
+ ConfigurablePrinter conf1 = new PrinterConfiguration().removeOption(ConfigOption.SPACE_AROUND_OPERATORS);
Statement statement1 = parseStatement("a = 1 + 1;");
assertEquals("a=1+1;", print(statement1, conf1));
}
@@ -125,19 +128,19 @@
*/
@Test
void printOperatorsR2(){
- PrettyPrinterConfiguration conf1 = new PrettyPrinterConfiguration().setSpaceAroundOperators(false);
+ ConfigurablePrinter conf1 = new PrinterConfiguration().removeOption(ConfigOption.SPACE_AROUND_OPERATORS);
Statement statement1 = parseStatement("a = 1 + 1;");
assertEquals("a=1+1;", print(statement1, conf1));
- PrettyPrinterConfiguration conf2 = new PrettyPrinterConfiguration().setSpaceAroundOperators(false);
+ ConfigurablePrinter conf2 = new PrinterConfiguration().removeOption(ConfigOption.SPACE_AROUND_OPERATORS);
Statement statement2 = parseStatement("a=1+1;");
assertEquals("a=1+1;", print(statement2, conf2));
- PrettyPrinterConfiguration conf3 = new PrettyPrinterConfiguration().setSpaceAroundOperators(true);
+ ConfigurablePrinter conf3 = new PrinterConfiguration().addOption(ConfigOption.SPACE_AROUND_OPERATORS);
Statement statement3 = parseStatement("a = 1 + 1;");
assertEquals("a = 1 + 1;", print(statement3, conf3));
- PrettyPrinterConfiguration conf4 = new PrettyPrinterConfiguration().setSpaceAroundOperators(true);
+ ConfigurablePrinter conf4 = new PrinterConfiguration().addOption(ConfigOption.SPACE_AROUND_OPERATORS);
Statement statement4 = parseStatement("a=1+1;");
assertEquals("a = 1 + 1;", print(statement4, conf4));
@@ -145,7 +148,7 @@
@Test
void printOperatorA(){
- PrettyPrinterConfiguration conf = new PrettyPrinterConfiguration().setSpaceAroundOperators(false);
+ ConfigurablePrinter conf = new PrinterConfiguration().removeOption(ConfigOption.SPACE_AROUND_OPERATORS);
Statement statement6 = parseStatement("if(1>2&&1<3||1<3){}");
assertEquals("if (1>2&&1<3||1<3) {" + SYSTEM_EOL
+ "}", print(statement6, conf));
@@ -154,7 +157,7 @@
@Test
void printOperator2(){
Expression expression = parseExpression("1+1");
- PrettyPrinterConfiguration spaces = new PrettyPrinterConfiguration().setSpaceAroundOperators(false);
+ ConfigurablePrinter spaces = new PrinterConfiguration().removeOption(ConfigOption.SPACE_AROUND_OPERATORS);
assertEquals("1+1", print(expression, spaces));
}
@@ -231,7 +234,7 @@
void printClassWithoutJavaDocButWithComment() {
String code = String.format("/** javadoc */ public class A { %s// stuff%s}", SYSTEM_EOL, SYSTEM_EOL);
CompilationUnit cu = parse(code);
- PrettyPrinterConfiguration ignoreJavaDoc = new PrettyPrinterConfiguration().setPrintJavadoc(false);
+ ConfigurablePrinter ignoreJavaDoc = new PrinterConfiguration().removeOption(ConfigOption.PRINT_JAVADOC);
String content = cu.toString(ignoreJavaDoc);
assertEquals(String.format("public class A {%s // stuff%s}%s", SYSTEM_EOL, SYSTEM_EOL, SYSTEM_EOL), content);
}
@@ -253,7 +256,7 @@
void printImportsOrdered() {
String code = "import x.y.z;import a.b.c;import static b.c.d;class c {}";
CompilationUnit cu = parse(code);
- PrettyPrinterConfiguration orderImports = new PrettyPrinterConfiguration().setOrderImports(true);
+ ConfigurablePrinter orderImports = new PrinterConfiguration().addOption(ConfigOption.ORDER_IMPORTS);
String content = cu.toString(orderImports);
assertEqualsStringIgnoringEol("import static b.c.d;\n" +
"import a.b.c;\n" +
diff --git a/javaparser-core-testing/src/test/java/com/github/javaparser/printer/PrettyPrintableTest.java b/javaparser-core-testing/src/test/java/com/github/javaparser/printer/PrettyPrintableTest.java
new file mode 100755
index 0000000..d9e212e
--- /dev/null
+++ b/javaparser-core-testing/src/test/java/com/github/javaparser/printer/PrettyPrintableTest.java
@@ -0,0 +1,578 @@
+/*
+ * Copyright (C) 2007-2010 Júlio Vilmar Gesser.
+ * Copyright (C) 2011, 2013-2019 The JavaParser Team.
+ *
+ * This file is part of JavaParser.
+ *
+ * JavaParser can be used either under the terms of
+ * a) the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ * b) the terms of the Apache License
+ *
+ * You should have received a copy of both licenses in LICENCE.LGPL and
+ * LICENCE.APACHE. Please refer to those files for details.
+ *
+ * JavaParser is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ */
+
+package com.github.javaparser.printer;
+
+import static com.github.javaparser.ParseStart.COMPILATION_UNIT;
+import static com.github.javaparser.ParserConfiguration.LanguageLevel.JAVA_9;
+import static com.github.javaparser.Providers.provider;
+import static com.github.javaparser.StaticJavaParser.parse;
+import static com.github.javaparser.StaticJavaParser.parseBodyDeclaration;
+import static com.github.javaparser.StaticJavaParser.parseStatement;
+import static com.github.javaparser.utils.TestUtils.assertEqualsStringIgnoringEol;
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+
+import org.junit.jupiter.api.Disabled;
+import org.junit.jupiter.api.Test;
+
+import com.github.javaparser.JavaParser;
+import com.github.javaparser.ParseProblemException;
+import com.github.javaparser.ParseResult;
+import com.github.javaparser.ParserConfiguration;
+import com.github.javaparser.StaticJavaParser;
+import com.github.javaparser.ast.CompilationUnit;
+import com.github.javaparser.ast.body.ClassOrInterfaceDeclaration;
+import com.github.javaparser.ast.body.FieldDeclaration;
+import com.github.javaparser.ast.body.TypeDeclaration;
+import com.github.javaparser.ast.expr.VariableDeclarationExpr;
+import com.github.javaparser.ast.stmt.Statement;
+import com.github.javaparser.ast.type.PrimitiveType;
+import com.github.javaparser.printer.configuration.ConfigurablePrinter;
+import com.github.javaparser.printer.configuration.Indentation;
+import com.github.javaparser.printer.configuration.Indentation.IndentType;
+import com.github.javaparser.printer.configuration.PrinterConfiguration;
+import com.github.javaparser.printer.configuration.PrinterConfiguration.ConfigOption;
+
+class PrettyPrintableTest {
+
+ private Printable getDefaultPrinter() {
+ ConfigurablePrinter configuration = new PrinterConfiguration();
+ return new PrettyPrintable(configuration);
+ }
+
+ private Printable getDefaultPrinter(ConfigurablePrinter configuration) {
+ return new PrettyPrintable(configuration);
+ }
+
+ private String prettyPrintField(String code) {
+ CompilationUnit cu = parse(code);
+ return getDefaultPrinter().print(cu.findFirst(FieldDeclaration.class).get());
+ }
+
+ private String prettyPrintVar(String code) {
+ CompilationUnit cu = parse(code);
+ return getDefaultPrinter().print(cu.findAll(VariableDeclarationExpr.class).get(0));
+ }
+
+ @Test
+ void printingArrayFields() {
+ String code;
+ code = "class A { int a, b[]; }";
+ assertEquals("int a, b[];", prettyPrintField(code));
+
+ code = "class A { int[] a[], b[]; }";
+ assertEquals("int[][] a, b;", prettyPrintField(code));
+
+ code = "class A { int[] a[][], b; }";
+ assertEquals("int[] a[][], b;", prettyPrintField(code));
+
+ code = "class A { int[] a, b; }";
+ assertEquals("int[] a, b;", prettyPrintField(code));
+
+ code = "class A { int a[], b[]; }";
+ assertEquals("int[] a, b;", prettyPrintField(code));
+ }
+
+ @Test
+ void printingArrayVariables() {
+ String code;
+ code = "class A { void foo(){ int a, b[]; }}";
+ assertEquals("int a, b[]", prettyPrintVar(code));
+
+ code = "class A { void foo(){ int[] a[], b[]; }}";
+ assertEquals("int[][] a, b", prettyPrintVar(code));
+
+ code = "class A { void foo(){ int[] a[][], b; }}";
+ assertEquals("int[] a[][], b", prettyPrintVar(code));
+
+ code = "class A { void foo(){ int[] a, b; }}";
+ assertEquals("int[] a, b", prettyPrintVar(code));
+
+ code = "class A { void foo(){ int a[], b[]; }}";
+ assertEquals("int[] a, b", prettyPrintVar(code));
+ }
+
+ @Disabled
+ private String prettyPrintConfigurable(String code) {
+ CompilationUnit cu = parse(code);
+ return getDefaultPrinter().print(cu.findFirst(ClassOrInterfaceDeclaration.class).get().getName());
+ }
+
+ @Test
+ void printUseTestVisitor() {
+ String code;
+ code = "class A { void foo(){ int a, b[]; }}";
+ assertEquals("A", prettyPrintConfigurable(code));
+ }
+
+ @Test
+ void prettyColumnAlignParameters_enabled() {
+ ConfigurablePrinter configuration = new PrinterConfiguration()
+ .addOption(ConfigOption.COLUMN_ALIGN_FIRST_METHOD_CHAIN)
+ .addOption(ConfigOption.COLUMN_ALIGN_PARAMETERS);
+
+ final String EOL = configuration.get(ConfigOption.END_OF_LINE_CHARACTER).get().asString();
+
+ String code = "class Example { void foo(Object arg0,Object arg1){ myMethod(1, 2, 3, 5, Object.class); } }";
+ String expected = "class Example {" + EOL +
+ "" + EOL +
+ " void foo(Object arg0, Object arg1) {" + EOL +
+ " myMethod(1," + EOL +
+ " 2," + EOL +
+ " 3," + EOL +
+ " 5," + EOL +
+ " Object.class);" + EOL +
+ " }" + EOL +
+ "}" + EOL +
+ "";
+
+ assertEquals(expected, getDefaultPrinter(configuration).print(parse(code)));
+ }
+
+ @Test
+ void prettyColumnAlignParameters_disabled() {
+
+ ConfigurablePrinter configuration = new PrinterConfiguration();
+ final String EOL = configuration.get(ConfigOption.END_OF_LINE_CHARACTER).get().asString();
+
+ String code = "class Example { void foo(Object arg0,Object arg1){ myMethod(1, 2, 3, 5, Object.class); } }";
+ String expected = "class Example {" + EOL +
+ "" + EOL +
+ " void foo(Object arg0, Object arg1) {" + EOL +
+ " myMethod(1, 2, 3, 5, Object.class);" + EOL +
+ " }" + EOL +
+ "}" + EOL +
+ "";
+
+ assertEquals(expected, getDefaultPrinter(configuration).print(parse(code)));
+ }
+
+ @Test
+ void prettyAlignMethodCallChains_enabled() {
+
+ ConfigurablePrinter configuration = new PrinterConfiguration()
+ .addOption(ConfigOption.COLUMN_ALIGN_FIRST_METHOD_CHAIN);
+
+ final String EOL = configuration.get(ConfigOption.END_OF_LINE_CHARACTER).get().asString();
+
+ String code = "class Example { void foo() { IntStream.range(0, 10).filter(x -> x % 2 == 0).map(x -> x * IntStream.of(1,3,5,1).sum()).forEach(System.out::println); } }";
+ String expected = "class Example {" + EOL +
+ "" + EOL +
+ " void foo() {" + EOL +
+ " IntStream.range(0, 10)" + EOL +
+ " .filter(x -> x % 2 == 0)" + EOL +
+ " .map(x -> x * IntStream.of(1, 3, 5, 1)" + EOL +
+ " .sum())" + EOL +
+ " .forEach(System.out::println);" + EOL +
+ " }" + EOL +
+ "}" + EOL +
+ "";
+
+ String printed = getDefaultPrinter(configuration).print(parse(code));
+ System.out.println(printed);
+
+ assertEquals(expected, printed);
+ }
+
+ @Test
+ void prettyAlignMethodCallChains_disabled() {
+
+ ConfigurablePrinter configuration = new PrinterConfiguration();
+ final String EOL = configuration.get(ConfigOption.END_OF_LINE_CHARACTER).get().asString();
+
+ String code = "class Example { void foo() { IntStream.range(0, 10).filter(x -> x % 2 == 0).map(x -> x * IntStream.of(1,3,5,1).sum()).forEach(System.out::println); } }";
+ String expected = "class Example {" + EOL +
+ "" + EOL +
+ " void foo() {" + EOL +
+ " IntStream.range(0, 10).filter(x -> x % 2 == 0).map(x -> x * IntStream.of(1, 3, 5, 1).sum()).forEach(System.out::println);" + EOL +
+ " }" + EOL +
+ "}" + EOL +
+ "";
+
+ assertEquals(expected, getDefaultPrinter(configuration).print(parse(code)));
+ }
+
+ @Test
+ void enumConstantsHorizontally() {
+ CompilationUnit cu = parse("enum X{A, B, C, D, E}");
+ assertEqualsStringIgnoringEol("enum X {\n\n A, B, C, D, E\n}\n", new PrettyPrintable().print(cu));
+ }
+
+ @Test
+ void enumConstantsVertically() {
+ CompilationUnit cu = parse("enum X{A, B, C, D, E, F}");
+ assertEqualsStringIgnoringEol("enum X {\n\n A,\n B,\n C,\n D,\n E,\n F\n}\n", new PrettyPrintable().print(cu));
+ }
+
+ @Test
+ void printingInconsistentVariables() {
+ FieldDeclaration fieldDeclaration = parseBodyDeclaration("int a, b;").asFieldDeclaration();
+
+ assertEquals("int a, b;", fieldDeclaration.toString());
+
+ fieldDeclaration.getVariable(0).setType(PrimitiveType.doubleType());
+
+ assertEquals("??? a, b;", fieldDeclaration.toString());
+
+ fieldDeclaration.getVariable(1).setType(PrimitiveType.doubleType());
+
+ assertEquals("double a, b;", fieldDeclaration.toString());
+ }
+
+ @Test
+ void prettyAlignMethodCallChainsIndentsArgumentsWithBlocksCorrectly() {
+
+ CompilationUnit cu = parse("class Foo { void bar() { a.b.c.d.e; a.b.c().d().e(); a.b.c().d.e(); foo().bar().baz(boo().baa().bee()).bam(); foo().bar().baz(boo().baa().bee()).bam; foo().bar(Long.foo().b.bar(), bam).baz(); foo().bar().baz(foo, () -> { boo().baa().bee(); }).baz(() -> { boo().baa().bee(); }).bam(() -> { boo().baa().bee(); }); } }");
+
+ Indentation indentation = new Indentation(IndentType.TABS_WITH_SPACE_ALIGN, 1);
+ ConfigurablePrinter configuration = new PrinterConfiguration()
+ .addOption(ConfigOption.COLUMN_ALIGN_FIRST_METHOD_CHAIN)
+ .addOption(ConfigOption.COLUMN_ALIGN_PARAMETERS)
+ .setIndentation(indentation);
+ String printed = getDefaultPrinter(configuration).print(cu);
+
+ assertEqualsStringIgnoringEol("class Foo {\n" +
+ "\n" +
+ "\tvoid bar() {\n" +
+ "\t\ta.b.c.d.e;\n" +
+ "\t\ta.b.c()\n" +
+ "\t\t .d()\n" +
+ "\t\t .e();\n" +
+ "\t\ta.b.c().d\n" +
+ "\t\t .e();\n" +
+ "\t\tfoo().bar()\n" +
+ "\t\t .baz(boo().baa().bee())\n" +
+ "\t\t .bam();\n" +
+ "\t\tfoo().bar()\n" +
+ "\t\t .baz(boo().baa().bee()).bam;\n" +
+ "\t\tfoo().bar(Long.foo().b.bar(),\n" +
+ "\t\t bam)\n" +
+ "\t\t .baz();\n" +
+ "\t\tfoo().bar()\n" +
+ "\t\t .baz(foo,\n" +
+ "\t\t () -> {\n" +
+ "\t\t \tboo().baa()\n" +
+ "\t\t \t .bee();\n" +
+ "\t\t })\n" +
+ "\t\t .baz(() -> {\n" +
+ "\t\t \tboo().baa()\n" +
+ "\t\t \t .bee();\n" +
+ "\t\t })\n" +
+ "\t\t .bam(() -> {\n" +
+ "\t\t \tboo().baa()\n" +
+ "\t\t \t .bee();\n" +
+ "\t\t });\n" +
+ "\t}\n" +
+ "}\n", printed);
+ }
+
+ @Test
+ void noChainsIndentsInIf() {
+ Statement cu = parseStatement("if (x.y().z()) { boo().baa().bee(); }");
+
+ ConfigurablePrinter configuration = new PrinterConfiguration().addOption(ConfigOption.COLUMN_ALIGN_FIRST_METHOD_CHAIN);
+ String printed = getDefaultPrinter(configuration).print(cu);
+
+ assertEqualsStringIgnoringEol("if (x.y().z()) {\n" +
+ " boo().baa()\n" +
+ " .bee();\n" +
+ "}", printed);
+ }
+
+ @Test
+ void noChainsIndentsInFor() {
+ Statement cu = parseStatement("for(int x=1; x.y().z(); x.z().z()) { boo().baa().bee(); }");
+
+ ConfigurablePrinter configuration = new PrinterConfiguration().addOption(ConfigOption.COLUMN_ALIGN_FIRST_METHOD_CHAIN);
+ String printed = getDefaultPrinter(configuration).print(cu);
+
+ assertEqualsStringIgnoringEol("for (int x = 1; x.y().z(); x.z().z()) {\n" +
+ " boo().baa()\n" +
+ " .bee();\n" +
+ "}", printed);
+ }
+
+ @Test
+ void noChainsIndentsInWhile() {
+ Statement cu = parseStatement("while(x.y().z()) { boo().baa().bee(); }");
+
+ ConfigurablePrinter configuration = new PrinterConfiguration()
+ .addOption(ConfigOption.COLUMN_ALIGN_FIRST_METHOD_CHAIN);
+ String printed = getDefaultPrinter(configuration).print(cu);
+
+ assertEqualsStringIgnoringEol("while (x.y().z()) {\n" +
+ " boo().baa()\n" +
+ " .bee();\n" +
+ "}", printed);
+ }
+
+ @Test
+ void indentWithTabsAsFarAsPossible() {
+
+ CompilationUnit cu = parse("class Foo { void bar() { foo().bar().baz(() -> { boo().baa().bee(a, b, c); }).bam(); } }");
+
+ Indentation indentation = new Indentation(IndentType.TABS, 1);
+ ConfigurablePrinter configuration = new PrinterConfiguration()
+ .addOption(ConfigOption.COLUMN_ALIGN_FIRST_METHOD_CHAIN)
+ .addOption(ConfigOption.COLUMN_ALIGN_PARAMETERS)
+ .setIndentation(indentation);
+
+ String printed = getDefaultPrinter(configuration).print(cu);
+
+ assertEqualsStringIgnoringEol("class Foo {\n" +
+ "\n" +
+ "\tvoid bar() {\n" +
+ "\t\tfoo().bar()\n" +
+ "\t\t\t .baz(() -> {\n" +
+ "\t\t\t\t boo().baa()\n" +
+ "\t\t\t\t\t .bee(a,\n" +
+ "\t\t\t\t\t\t b,\n" +
+ "\t\t\t\t\t\t c);\n" +
+ "\t\t\t })\n" +
+ "\t\t\t .bam();\n" +
+ "\t}\n" +
+ "}\n", printed);
+ }
+
+ @Test
+ void indentWithTabsAlignWithSpaces() {
+
+ CompilationUnit cu = parse("class Foo { void bar() { foo().bar().baz(() -> { boo().baa().bee(a, b, c); }).baz(() -> { return boo().baa(); }).bam(); } }");
+
+ Indentation indentation = new Indentation(IndentType.TABS_WITH_SPACE_ALIGN, 1);
+ ConfigurablePrinter configuration = new PrinterConfiguration()
+ .addOption(ConfigOption.COLUMN_ALIGN_FIRST_METHOD_CHAIN)
+ .addOption(ConfigOption.COLUMN_ALIGN_PARAMETERS)
+ .setIndentation(indentation);
+
+ String printed = getDefaultPrinter(configuration).print(cu);
+
+ assertEqualsStringIgnoringEol("class Foo {\n" +
+ "\n" +
+ "\tvoid bar() {\n" +
+ "\t\tfoo().bar()\n" +
+ "\t\t .baz(() -> {\n" +
+ "\t\t \tboo().baa()\n" +
+ "\t\t \t .bee(a,\n" +
+ "\t\t \t b,\n" +
+ "\t\t \t c);\n" +
+ "\t\t })\n" +
+ "\t\t .baz(() -> {\n" +
+ "\t\t \treturn boo().baa();\n" +
+ "\t\t })\n" +
+ "\t\t .bam();\n" +
+ "\t}\n" +
+ "}\n", printed);
+ }
+
+ @Test
+ void printAnnotationsAtPrettyPlaces() {
+
+ JavaParser javaParser = new JavaParser(new ParserConfiguration().setLanguageLevel(JAVA_9));
+ ParseResult<CompilationUnit> parseResult = javaParser.parse(COMPILATION_UNIT, provider("@Documented\n" +
+ "@Repeatable\n" +
+ "package com.github.javaparser;\n" +
+ "\n" +
+ "import java.lang.annotation.Documented;\n" +
+ "import java.lang.annotation.Repeatable;\n" +
+ "\n" +
+ "@Documented\n" +
+ "@Repeatable\n" +
+ "@interface Annotation {\n" +
+ "\n" +
+ " @Documented\n" +
+ " @Repeatable\n" +
+ " String value();\n" +
+ "}\n" +
+ "\n" +
+ "@Documented\n" +
+ "@Repeatable\n" +
+ "class Class<@Documented @Repeatable T> {\n" +
+ "\n" +
+ " @Documented\n" +
+ " @Repeatable\n" +
+ " byte b;\n" +
+ "\n" +
+ " @Documented\n" +
+ " @Repeatable\n" +
+ " Class(@Documented @Repeatable int i) {\n" +
+ " @Documented\n" +
+ " @Repeatable\n" +
+ " short s;\n" +
+ " }\n" +
+ "\n" +
+ " @Documented\n" +
+ " @Repeatable\n" +
+ " void method(@Documented @Repeatable Class this) {\n" +
+ " for (@Deprecated int i : arr4[0]) {\n" +
+ " x--;\n" +
+ " }\n" +
+ " }\n" +
+ "\n" +
+ " void method(@Documented @Repeatable Class this, int i) {\n" +
+ " }\n" +
+ "}\n" +
+ "\n" +
+ "@Documented\n" +
+ "@Repeatable\n" +
+ "enum Foo {\n" +
+ "\n" +
+ " @Documented\n" +
+ " @Repeatable\n" +
+ " BAR\n" +
+ "}\n" +
+ "@Documented\n" +
+ "@Repeatable\n" +
+ "module foo.bar {\n" +
+ "}\n"));
+ if (!parseResult.isSuccessful()) {
+ throw new ParseProblemException(parseResult.getProblems());
+ }
+ CompilationUnit cu = parseResult.getResult().orElseThrow(AssertionError::new);
+ String printed = getDefaultPrinter().print(cu);
+
+ assertEqualsStringIgnoringEol("@Documented\n" +
+ "@Repeatable\n" +
+ "package com.github.javaparser;\n" +
+ "\n" +
+ "import java.lang.annotation.Documented;\n" +
+ "import java.lang.annotation.Repeatable;\n" +
+ "\n" +
+ "@Documented\n" +
+ "@Repeatable\n" +
+ "@interface Annotation {\n" +
+ "\n" +
+ " @Documented\n" +
+ " @Repeatable\n" +
+ " String value();\n" +
+ "}\n" +
+ "\n" +
+ "@Documented\n" +
+ "@Repeatable\n" +
+ "class Class<@Documented @Repeatable T> {\n" +
+ "\n" +
+ " @Documented\n" +
+ " @Repeatable\n" +
+ " byte b;\n" +
+ "\n" +
+ " @Documented\n" +
+ " @Repeatable\n" +
+ " Class(@Documented @Repeatable int i) {\n" +
+ " @Documented\n" +
+ " @Repeatable\n" +
+ " short s;\n" +
+ " }\n" +
+ "\n" +
+ " @Documented\n" +
+ " @Repeatable\n" +
+ " void method(@Documented @Repeatable Class this) {\n" +
+ " for (@Deprecated int i : arr4[0]) {\n" +
+ " x--;\n" +
+ " }\n" +
+ " }\n" +
+ "\n" +
+ " void method(@Documented @Repeatable Class this, int i) {\n" +
+ " }\n" +
+ "}\n" +
+ "\n" +
+ "@Documented\n" +
+ "@Repeatable\n" +
+ "enum Foo {\n" +
+ "\n" +
+ " @Documented\n" +
+ " @Repeatable\n" +
+ " BAR\n" +
+ "}\n" +
+ "@Documented\n" +
+ "@Repeatable\n" +
+ "module foo.bar {\n" +
+ "}\n", printed);
+ }
+
+ @Test
+ public void testIssue2578() {
+ String code =
+ "class C{\n" +
+ " //orphan\n" +
+ " /*orphan*/\n" +
+ "}";
+ CompilationUnit cu = StaticJavaParser.parse(code);
+ TypeDeclaration td = cu.findFirst(TypeDeclaration.class).get();
+ assertEquals(2, td.getAllContainedComments().size());
+ td.setPublic(true); // --- simple AST change -----
+ System.out.println(cu.toString()); // orphan and /*orphan*/ must be printed
+ assertEquals(2, td.getAllContainedComments().size()); // the orphaned comments exist
+ }
+
+ @Test
+ public void testIssue2535() {
+
+ String code =
+ "public class A {\n" +
+ " public static A m() {\n" +
+ " System.out.println(\"\");\n" +
+ " // TODO\n" +
+ " /* TODO */\n" +
+ " /** TODO */\n" +
+ " }\n" +
+ "}";
+
+ StaticJavaParser.setConfiguration(new ParserConfiguration());
+
+ CompilationUnit cu = StaticJavaParser.parse(code);
+
+ // default indent is 4 spaces
+ assertTrue(cu.toString().contains(" // TODO"));
+ assertTrue(cu.toString().contains(" /* TODO */"));
+
+ }
+
+ @Test
+ public void testIndentationWithDefaultSize() {
+ Indentation indentation = new Indentation(IndentType.SPACES);
+ assertTrue(indentation.getSize()==4);
+ assertEquals(" ", indentation.getIndent());
+ // on-the-fly modification
+ indentation.setSize(2);
+ assertTrue(indentation.getSize()==2);
+ assertEquals(" ", indentation.getIndent());
+ }
+
+ @Test
+ public void testIndentationWithCustomSize() {
+ Indentation indentation = new Indentation(IndentType.TABS,2);
+ assertTrue(indentation.getSize()==2);
+ assertEquals("\t\t", indentation.getIndent());
+ }
+
+ @Test
+ public void testIndentationWithOnTheFlyModifcation() {
+ Indentation indentation = new Indentation(IndentType.SPACES);
+ // on-the-fly modification
+ indentation.setSize(2);
+ assertTrue(indentation.getSize()==2);
+ assertEquals(" ", indentation.getIndent());
+ indentation.setType(IndentType.TABS);
+ assertTrue(indentation.getType() == IndentType.TABS);
+ assertEquals("\t\t", indentation.getIndent());
+ }
+}
diff --git a/javaparser-core-testing/src/test/java/com/github/javaparser/printer/PrettyPrinterTest.java b/javaparser-core-testing/src/test/java/com/github/javaparser/printer/PrettyPrinterTest.java
index a772f79..5e75591 100644
--- a/javaparser-core-testing/src/test/java/com/github/javaparser/printer/PrettyPrinterTest.java
+++ b/javaparser-core-testing/src/test/java/com/github/javaparser/printer/PrettyPrinterTest.java
@@ -33,6 +33,8 @@
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertTrue;
+import java.util.function.Function;
+
import org.junit.jupiter.api.Test;
import com.github.javaparser.JavaParser;
@@ -47,19 +49,23 @@
import com.github.javaparser.ast.expr.VariableDeclarationExpr;
import com.github.javaparser.ast.stmt.Statement;
import com.github.javaparser.ast.type.PrimitiveType;
+import com.github.javaparser.ast.visitor.VoidVisitor;
+import com.github.javaparser.printer.configuration.ConfigurablePrinter;
import com.github.javaparser.printer.configuration.Indentation;
import com.github.javaparser.printer.configuration.Indentation.IndentType;
+import com.github.javaparser.printer.configuration.PrinterConfiguration;
+import com.github.javaparser.printer.configuration.PrinterConfiguration.ConfigOption;
class PrettyPrinterTest {
private String prettyPrintField(String code) {
CompilationUnit cu = parse(code);
- return new PrettyPrinter().print(cu.findFirst(FieldDeclaration.class).get());
+ return new PrettyPrintable().print(cu.findFirst(FieldDeclaration.class).get());
}
private String prettyPrintVar(String code) {
CompilationUnit cu = parse(code);
- return new PrettyPrinter().print(cu.findAll(VariableDeclarationExpr.class).get(0));
+ return new PrettyPrintable().print(cu.findAll(VariableDeclarationExpr.class).get(0));
}
@Test
@@ -102,7 +108,9 @@
private String prettyPrintConfigurable(String code) {
CompilationUnit cu = parse(code);
- Printable printer = new PrettyPrinter(new PrettyPrinterConfiguration().setVisitorFactory(TestVisitor::new));
+ ConfigurablePrinter configuration = new PrinterConfiguration();
+ Function<ConfigurablePrinter, VoidVisitor<Void>> visitorFactory = (config) -> new TestVisitor(config, new DefaultPrintableSource(config));
+ Printable printer = new PrettyPrintable(visitorFactory, configuration);
return printer.print(cu.findFirst(ClassOrInterfaceDeclaration.class).get());
}
@@ -115,11 +123,9 @@
@Test
void prettyColumnAlignParameters_enabled() {
- PrettyPrinterConfiguration config = new PrettyPrinterConfiguration()
- .setColumnAlignParameters(true);
-
- final String EOL = config.getEndOfLineCharacter();
-
+ ConfigurablePrinter config = new PrinterConfiguration().addOption(ConfigOption.COLUMN_ALIGN_PARAMETERS);
+ final String EOL = config.get(ConfigOption.END_OF_LINE_CHARACTER).get().asValue();
+
String code = "class Example { void foo(Object arg0,Object arg1){ myMethod(1, 2, 3, 5, Object.class); } }";
String expected = "class Example {" + EOL +
"" + EOL +
@@ -133,13 +139,14 @@
"}" + EOL +
"";
- assertEquals(expected, new PrettyPrinter(config).print(parse(code)));
+ assertEquals(expected, new PrettyPrintable(config).print(parse(code)));
}
@Test
void prettyColumnAlignParameters_disabled() {
- PrettyPrinterConfiguration config = new PrettyPrinterConfiguration();
- final String EOL = config.getEndOfLineCharacter();
+
+ ConfigurablePrinter config = new PrinterConfiguration();
+ final String EOL = config.get(ConfigOption.END_OF_LINE_CHARACTER).get().asValue();
String code = "class Example { void foo(Object arg0,Object arg1){ myMethod(1, 2, 3, 5, Object.class); } }";
String expected = "class Example {" + EOL +
@@ -150,15 +157,14 @@
"}" + EOL +
"";
- assertEquals(expected, new PrettyPrinter(config).print(parse(code)));
+ assertEquals(expected, new PrettyPrintable(config).print(parse(code)));
}
@Test
void prettyAlignMethodCallChains_enabled() {
- PrettyPrinterConfiguration config = new PrettyPrinterConfiguration()
- .setColumnAlignFirstMethodChain(true);
-
- final String EOL = config.getEndOfLineCharacter();
+
+ ConfigurablePrinter config = new PrinterConfiguration().addOption(ConfigOption.COLUMN_ALIGN_FIRST_METHOD_CHAIN);
+ final String EOL = config.get(ConfigOption.END_OF_LINE_CHARACTER).get().asValue();
String code = "class Example { void foo() { IntStream.range(0, 10).filter(x -> x % 2 == 0).map(x -> x * IntStream.of(1,3,5,1).sum()).forEach(System.out::println); } }";
String expected = "class Example {" + EOL +
@@ -173,13 +179,14 @@
"}" + EOL +
"";
- assertEquals(expected, new PrettyPrinter(config).print(parse(code)));
+ assertEquals(expected, new PrettyPrintable(config).print(parse(code)));
}
@Test
void prettyAlignMethodCallChains_disabled() {
- PrettyPrinterConfiguration config = new PrettyPrinterConfiguration();
- final String EOL = config.getEndOfLineCharacter();
+
+ ConfigurablePrinter config = new PrinterConfiguration();
+ final String EOL = config.get(ConfigOption.END_OF_LINE_CHARACTER).get().asValue();
String code = "class Example { void foo() { IntStream.range(0, 10).filter(x -> x % 2 == 0).map(x -> x * IntStream.of(1,3,5,1).sum()).forEach(System.out::println); } }";
String expected = "class Example {" + EOL +
@@ -190,19 +197,21 @@
"}" + EOL +
"";
- assertEquals(expected, new PrettyPrinter(config).print(parse(code)));
+ String printed = new PrettyPrintable(config).print(parse(code));
+
+ assertEquals(expected, printed);
}
@Test
void enumConstantsHorizontally() {
CompilationUnit cu = parse("enum X{A, B, C, D, E}");
- assertEqualsStringIgnoringEol("enum X {\n\n A, B, C, D, E\n}\n", new PrettyPrinter().print(cu));
+ assertEqualsStringIgnoringEol("enum X {\n\n A, B, C, D, E\n}\n", new PrettyPrintable().print(cu));
}
@Test
void enumConstantsVertically() {
CompilationUnit cu = parse("enum X{A, B, C, D, E, F}");
- assertEqualsStringIgnoringEol("enum X {\n\n A,\n B,\n C,\n D,\n E,\n F\n}\n", new PrettyPrinter().print(cu));
+ assertEqualsStringIgnoringEol("enum X {\n\n A,\n B,\n C,\n D,\n E,\n F\n}\n", new PrettyPrintable().print(cu));
}
@Test
@@ -225,9 +234,14 @@
CompilationUnit cu = parse("class Foo { void bar() { a.b.c.d.e; a.b.c().d().e(); a.b.c().d.e(); foo().bar().baz(boo().baa().bee()).bam(); foo().bar().baz(boo().baa().bee()).bam; foo().bar(Long.foo().b.bar(), bam).baz(); foo().bar().baz(foo, () -> { boo().baa().bee(); }).baz(() -> { boo().baa().bee(); }).bam(() -> { boo().baa().bee(); }); } }");
Indentation indentation = new Indentation(TABS_WITH_SPACE_ALIGN, 1);
- String printed = new PrettyPrinter(new PrettyPrinterConfiguration().setColumnAlignFirstMethodChain(true).setColumnAlignParameters(true).setIndentation(indentation))
- .print(cu);
+ ConfigurablePrinter config = new PrinterConfiguration()
+ .addOption(ConfigOption.COLUMN_ALIGN_FIRST_METHOD_CHAIN)
+ .addOption(ConfigOption.COLUMN_ALIGN_PARAMETERS)
+ .setIndentation(indentation);
+
+ String printed = new PrettyPrintable(config).print(cu);
+
assertEqualsStringIgnoringEol("class Foo {\n" +
"\n" +
"\tvoid bar() {\n" +
@@ -267,7 +281,8 @@
void noChainsIndentsInIf() {
Statement cu = parseStatement("if (x.y().z()) { boo().baa().bee(); }");
- String printed = new PrettyPrinter(new PrettyPrinterConfiguration().setColumnAlignFirstMethodChain(true))
+ String printed = new PrettyPrintable(new PrinterConfiguration()
+ .addOption(ConfigOption.COLUMN_ALIGN_FIRST_METHOD_CHAIN))
.print(cu);
assertEqualsStringIgnoringEol("if (x.y().z()) {\n" +
@@ -280,7 +295,8 @@
void noChainsIndentsInFor() {
Statement cu = parseStatement("for(int x=1; x.y().z(); x.z().z()) { boo().baa().bee(); }");
- String printed = new PrettyPrinter(new PrettyPrinterConfiguration().setColumnAlignFirstMethodChain(true))
+ String printed = new PrettyPrintable(new PrinterConfiguration()
+ .addOption(ConfigOption.COLUMN_ALIGN_FIRST_METHOD_CHAIN))
.print(cu);
assertEqualsStringIgnoringEol("for (int x = 1; x.y().z(); x.z().z()) {\n" +
@@ -293,7 +309,8 @@
void noChainsIndentsInWhile() {
Statement cu = parseStatement("while(x.y().z()) { boo().baa().bee(); }");
- String printed = new PrettyPrinter(new PrettyPrinterConfiguration().setColumnAlignFirstMethodChain(true))
+ String printed = new PrettyPrintable(new PrinterConfiguration()
+ .addOption(ConfigOption.COLUMN_ALIGN_FIRST_METHOD_CHAIN))
.print(cu);
assertEqualsStringIgnoringEol("while (x.y().z()) {\n" +
@@ -307,9 +324,9 @@
CompilationUnit cu = parse("class Foo { void bar() { foo().bar().baz(() -> { boo().baa().bee(a, b, c); }).bam(); } }");
Indentation indentation = new Indentation(TABS, 1);
- String printed = new PrettyPrinter(new PrettyPrinterConfiguration()
- .setColumnAlignFirstMethodChain(true)
- .setColumnAlignParameters(true)
+ String printed = new PrettyPrintable(new PrinterConfiguration()
+ .addOption(ConfigOption.COLUMN_ALIGN_FIRST_METHOD_CHAIN)
+ .addOption(ConfigOption.COLUMN_ALIGN_PARAMETERS)
.setIndentation(indentation))
.print(cu);
@@ -333,9 +350,9 @@
CompilationUnit cu = parse("class Foo { void bar() { foo().bar().baz(() -> { boo().baa().bee(a, b, c); }).baz(() -> { return boo().baa(); }).bam(); } }");
Indentation indentation = new Indentation(TABS_WITH_SPACE_ALIGN, 1);
- String printed = new PrettyPrinter(new PrettyPrinterConfiguration()
- .setColumnAlignFirstMethodChain(true)
- .setColumnAlignParameters(true)
+ String printed = new PrettyPrintable(new PrinterConfiguration()
+ .addOption(ConfigOption.COLUMN_ALIGN_FIRST_METHOD_CHAIN)
+ .addOption(ConfigOption.COLUMN_ALIGN_PARAMETERS)
.setIndentation(indentation))
.print(cu);
@@ -421,7 +438,7 @@
throw new ParseProblemException(parseResult.getProblems());
}
CompilationUnit cu = parseResult.getResult().orElseThrow(AssertionError::new);
- String printed = new PrettyPrinter().print(cu);
+ String printed = new PrettyPrintable().print(cu);
assertEqualsStringIgnoringEol("@Documented\n" +
"@Repeatable\n" +
diff --git a/javaparser-core-testing/src/test/java/com/github/javaparser/printer/PrinterConfigurationTest.java b/javaparser-core-testing/src/test/java/com/github/javaparser/printer/PrinterConfigurationTest.java
new file mode 100755
index 0000000..97e7501
--- /dev/null
+++ b/javaparser-core-testing/src/test/java/com/github/javaparser/printer/PrinterConfigurationTest.java
@@ -0,0 +1,67 @@
+package com.github.javaparser.printer;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertFalse;
+import static org.junit.jupiter.api.Assertions.assertThrows;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+
+import org.junit.jupiter.api.Test;
+
+import com.github.javaparser.printer.configuration.ConfigurablePrinter;
+import com.github.javaparser.printer.configuration.PrinterConfiguration;
+import com.github.javaparser.printer.configuration.PrinterConfiguration.ConfigOption;
+import com.github.javaparser.utils.Utils;
+
+class PrinterConfigurationTest {
+
+ @Test
+ void testDefaultConfigurationAndValue() {
+ ConfigurablePrinter config = new PrinterConfiguration();
+ assertTrue(config.get(ConfigOption.PRINT_COMMENTS).isPresent());
+ assertTrue(config.get(ConfigOption.PRINT_JAVADOC).isPresent());
+ assertTrue(config.get(ConfigOption.SPACE_AROUND_OPERATORS).isPresent());
+ assertTrue(config.get(ConfigOption.INDENT_CASE_IN_SWITCH).isPresent());
+ assertTrue(config.get(ConfigOption.DEFAULT_MAX_ENUM_CONSTANTS_TO_ALIGN_HORIZONTALLY).isPresent());
+ assertTrue(config.get(ConfigOption.END_OF_LINE_CHARACTER).isPresent());
+ // values
+ assertEquals(config.get(ConfigOption.DEFAULT_MAX_ENUM_CONSTANTS_TO_ALIGN_HORIZONTALLY).get().asValue(),
+ Integer.valueOf(5));
+ assertEquals(config.get(ConfigOption.DEFAULT_MAX_ENUM_CONSTANTS_TO_ALIGN_HORIZONTALLY).get().asValue(),
+ Integer.valueOf(5));
+ assertTrue(config.get(ConfigOption.DEFAULT_MAX_ENUM_CONSTANTS_TO_ALIGN_HORIZONTALLY).get().asValue() ==
+ Integer.valueOf(5));
+ assertEquals(config.get(ConfigOption.END_OF_LINE_CHARACTER).get().asString(), Utils.SYSTEM_EOL);
+ }
+
+ @Test
+ void testConfigurationError() {
+ ConfigurablePrinter config = new PrinterConfiguration();
+ // verify configuration error case
+ assertThrows(IllegalArgumentException.class, () -> {
+ config.get(ConfigOption.PRINT_COMMENTS).get().asValue();
+ });
+ }
+
+ @Test
+ void testUpdatedConfigurationOption() {
+ ConfigurablePrinter config = new PrinterConfiguration();
+ // change the default value of the DEFAULT_MAX_ENUM_CONSTANTS_TO_ALIGN_HORIZONTALLY option
+ config.get(ConfigOption.DEFAULT_MAX_ENUM_CONSTANTS_TO_ALIGN_HORIZONTALLY).get().value(2);
+ // verify the value is updated
+ assertEquals(config.get(ConfigOption.DEFAULT_MAX_ENUM_CONSTANTS_TO_ALIGN_HORIZONTALLY).get().asValue(), Integer.valueOf(2));
+ }
+
+ @Test
+ void testRemoveOption() {
+ ConfigurablePrinter config = new PrinterConfiguration();
+ assertTrue(config.get(ConfigOption.PRINT_COMMENTS).isPresent());
+ assertTrue(config.get(ConfigOption.END_OF_LINE_CHARACTER).isPresent());
+ // remove option PRINT_COMMENTS
+ config.removeOption(ConfigOption.PRINT_COMMENTS);
+ assertFalse(config.get(ConfigOption.PRINT_COMMENTS).isPresent());
+ // remove option with value
+ config.removeOption(ConfigOption.END_OF_LINE_CHARACTER.value("\n"));
+ assertFalse(config.get(ConfigOption.END_OF_LINE_CHARACTER).isPresent());
+ }
+
+}
diff --git a/javaparser-core-testing/src/test/java/com/github/javaparser/printer/TestVisitor.java b/javaparser-core-testing/src/test/java/com/github/javaparser/printer/TestVisitor.java
index cf3e557..65fcdbc 100644
--- a/javaparser-core-testing/src/test/java/com/github/javaparser/printer/TestVisitor.java
+++ b/javaparser-core-testing/src/test/java/com/github/javaparser/printer/TestVisitor.java
@@ -22,13 +22,14 @@
package com.github.javaparser.printer;
import com.github.javaparser.ast.body.ClassOrInterfaceDeclaration;
+import com.github.javaparser.printer.configuration.ConfigurablePrinter;
-public class TestVisitor extends PrettyPrintVisitor {
+public class TestVisitor extends PrintableVisitor {
- public TestVisitor(PrettyPrinterConfiguration prettyPrinterConfiguration) {
- super(prettyPrinterConfiguration);
+ public TestVisitor(ConfigurablePrinter configuration, PrintableSource printer) {
+ super(configuration, printer);
}
-
+
@Override
public void visit(final ClassOrInterfaceDeclaration n, final Void arg) {
printer.print("test");
diff --git a/javaparser-core-testing/src/test/java/com/github/javaparser/printer/lexicalpreservation/AATest.java b/javaparser-core-testing/src/test/java/com/github/javaparser/printer/lexicalpreservation/AATest.java
new file mode 100755
index 0000000..257d137
--- /dev/null
+++ b/javaparser-core-testing/src/test/java/com/github/javaparser/printer/lexicalpreservation/AATest.java
@@ -0,0 +1,51 @@
+package com.github.javaparser.printer.lexicalpreservation;
+
+/*
+ * Copyright (C) 2007-2010 Júlio Vilmar Gesser.
+ * Copyright (C) 2011, 2013-2019 The JavaParser Team.
+ *
+ * This file is part of JavaParser.
+ *
+ * JavaParser can be used either under the terms of
+ * a) the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ * b) the terms of the Apache License
+ *
+ * You should have received a copy of both licenses in LICENCE.LGPL and
+ * LICENCE.APACHE. Please refer to those files for details.
+ *
+ * JavaParser is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ */
+
+import org.junit.jupiter.api.Test;
+
+import com.github.javaparser.ParserConfiguration;
+import com.github.javaparser.StaticJavaParser;
+import com.github.javaparser.ast.CompilationUnit;
+import com.github.javaparser.ast.ImportDeclaration;
+import com.github.javaparser.ast.NodeList;
+
+public class AATest extends AbstractLexicalPreservingTest {
+
+ @Test
+ public void test() {
+ String actual =
+ "package com.wangym.test;\nclass A{ }";
+
+ StaticJavaParser.setConfiguration(new ParserConfiguration());
+
+ CompilationUnit cu = StaticJavaParser.parse(actual);
+ LexicalPreservingPrinter.setup(cu);
+
+ NodeList<ImportDeclaration> imports = cu.getImports();
+ String str = "lombok.Data";
+ imports.add(new ImportDeclaration(str, false, false));
+
+ System.out.println(LexicalPreservingPrinter.print(cu));
+ }
+
+}
diff --git a/javaparser-core/src/main/java/com/github/javaparser/ast/CompilationUnit.java b/javaparser-core/src/main/java/com/github/javaparser/ast/CompilationUnit.java
index 7522e35..fd32255 100644
--- a/javaparser-core/src/main/java/com/github/javaparser/ast/CompilationUnit.java
+++ b/javaparser-core/src/main/java/com/github/javaparser/ast/CompilationUnit.java
@@ -29,6 +29,7 @@
import static com.github.javaparser.ast.Modifier.createModifierList;
import static com.github.javaparser.utils.CodeGenerationUtils.subtractPaths;
import static com.github.javaparser.utils.Utils.assertNotNull;
+
import java.io.IOException;
import java.nio.charset.Charset;
import java.nio.file.Files;
@@ -39,6 +40,7 @@
import java.util.Optional;
import java.util.function.Function;
import java.util.stream.Collectors;
+
import com.github.javaparser.JavaParser;
import com.github.javaparser.JavaToken;
import com.github.javaparser.ParseResult;
@@ -62,7 +64,6 @@
import com.github.javaparser.metamodel.InternalProperty;
import com.github.javaparser.metamodel.JavaParserMetaModel;
import com.github.javaparser.metamodel.OptionalProperty;
-import com.github.javaparser.printer.PrettyPrinter;
import com.github.javaparser.printer.Printable;
import com.github.javaparser.utils.ClassUtils;
import com.github.javaparser.utils.CodeGenerationUtils;
@@ -99,6 +100,9 @@
@InternalProperty
private Storage storage;
+
+ // printer used to print the node
+ private Printable printer;
public CompilationUnit() {
this(null, null, new NodeList<>(), new NodeList<>(), null);
@@ -137,6 +141,25 @@
public <A> void accept(final VoidVisitor<A> v, final A arg) {
v.visit(this, arg);
}
+
+ /**
+ * Declare a specific printer
+ */
+ public CompilationUnit printer(Printable printer) {
+ this.printer = printer;
+ return this;
+ }
+
+ /*
+ * If there is no declared printer, returns a new default printer else returns a new printer with the current configuration
+ */
+ @Override
+ public Printable getPrinter() {
+ if (printer == null) {
+ printer = createDefaultPrinter();
+ }
+ return printer;
+ }
/**
* @deprecated getComments was a too generic name and it could be confused with getComment
@@ -684,8 +707,6 @@
private final Charset encoding;
- private Printable printer;
-
private Storage(CompilationUnit compilationUnit, Path path) {
this(compilationUnit, path, UTF8);
}
@@ -694,22 +715,6 @@
this.compilationUnit = compilationUnit;
this.path = path.toAbsolutePath();
this.encoding = encoding;
- // default printer
- this.printer = new PrettyPrinter();
- }
-
- /**
- * Set a new printer
- */
- public void setPrinter(Printable printer) {
- this.printer = printer;
- }
-
- /**
- * Returns the internal printer
- */
- public Printable getPrinter() {
- return this.printer;
}
/**
@@ -755,7 +760,7 @@
* Saves the compilation unit to its original location
*/
public void save() {
- save(cu -> printer.print(cu));
+ save(cu -> compilationUnit.getPrinter().print(cu));
}
/**
diff --git a/javaparser-core/src/main/java/com/github/javaparser/ast/Node.java b/javaparser-core/src/main/java/com/github/javaparser/ast/Node.java
index f4db8ed..9741f76 100644
--- a/javaparser-core/src/main/java/com/github/javaparser/ast/Node.java
+++ b/javaparser-core/src/main/java/com/github/javaparser/ast/Node.java
@@ -20,13 +20,13 @@
*/
package com.github.javaparser.ast;
-import com.github.javaparser.HasParentNode;
import static com.github.javaparser.ast.Node.Parsedness.PARSED;
import static com.github.javaparser.ast.Node.TreeTraversal.PREORDER;
import static java.util.Collections.emptySet;
import static java.util.Collections.unmodifiableList;
import static java.util.Spliterator.DISTINCT;
import static java.util.Spliterator.NONNULL;
+
import java.util.ArrayList;
import java.util.Comparator;
import java.util.HashSet;
@@ -44,6 +44,8 @@
import java.util.function.Predicate;
import java.util.stream.Stream;
import java.util.stream.StreamSupport;
+
+import com.github.javaparser.HasParentNode;
import com.github.javaparser.Position;
import com.github.javaparser.Range;
import com.github.javaparser.TokenRange;
@@ -64,8 +66,11 @@
import com.github.javaparser.metamodel.NodeMetaModel;
import com.github.javaparser.metamodel.OptionalProperty;
import com.github.javaparser.metamodel.PropertyMetaModel;
-import com.github.javaparser.printer.PrettyPrinter;
-import com.github.javaparser.printer.PrettyPrinterConfiguration;
+import com.github.javaparser.printer.PrettyPrintable;
+import com.github.javaparser.printer.Printable;
+import com.github.javaparser.printer.configuration.ConfigurablePrinter;
+import com.github.javaparser.printer.configuration.PrinterConfiguration;
+import com.github.javaparser.printer.configuration.PrinterConfiguration.ConfigOption;
import com.github.javaparser.resolution.SymbolResolver;
import com.github.javaparser.utils.LineSeparator;
@@ -157,10 +162,8 @@
return 0;
};
- private static PrettyPrinterConfiguration toStringPrettyPrinterConfiguration = new PrettyPrinterConfiguration();
-
- protected static final PrettyPrinterConfiguration prettyPrinterNoCommentsConfiguration = new PrettyPrinterConfiguration().setPrintComments(false);
-
+ protected static final ConfigurablePrinter prettyPrinterNoCommentsConfiguration = new PrinterConfiguration().removeOption(ConfigOption.PRINT_COMMENTS);
+
@InternalProperty
private Range range;
@@ -199,6 +202,37 @@
*/
protected void customInitialization() {
}
+
+ /*
+ * If there is a printer defined in CompilationUnit, returns it
+ * else create a new PrettyPrintable with default parameters
+ */
+ protected Printable getPrinter() {
+ Optional<CompilationUnit> cu = findCompilationUnit();
+ if (!cu.isPresent()) {
+ return createDefaultPrinter();
+ }
+ return cu.get().getPrinter();
+ }
+
+ /*
+ * Return the printer initialized with the specified configuration
+ */
+ protected Printable getPrinter(ConfigurablePrinter configuration) {
+ return getPrinter().setConfiguration(configuration);
+ }
+
+ protected Printable createDefaultPrinter() {
+ ConfigurablePrinter configuration = getDefaultPrinterConfiguration();
+ return new PrettyPrintable(configuration);
+ }
+
+ /*
+ * returns a default printer configuration
+ */
+ protected ConfigurablePrinter getDefaultPrinterConfiguration() {
+ return new PrinterConfiguration();
+ }
/**
* This is a comment associated with this node.
@@ -287,23 +321,24 @@
/**
* @return pretty printed source code for this node and its children.
- * Formatting can be configured with Node.setToStringPrettyPrinterConfiguration.
*/
@Override
public final String toString() {
if (containsData(LINE_SEPARATOR_KEY)) {
LineSeparator lineSeparator = getLineEndingStyleOrDefault(LineSeparator.SYSTEM);
- toStringPrettyPrinterConfiguration.setEndOfLineCharacter(lineSeparator.asRawString());
+ ConfigurablePrinter config = getDefaultPrinterConfiguration();
+ config.addOption(ConfigOption.END_OF_LINE_CHARACTER.value(lineSeparator.asRawString()));
+ return getPrinter(config).print(this);
}
- return new PrettyPrinter(toStringPrettyPrinterConfiguration).print(this);
+ return getPrinter().print(this);
}
/**
* @return pretty printed source code for this node and its children.
- * Formatting can be configured with parameter prettyPrinterConfiguration.
+ * Formatting can be configured with parameter ConfigurablePrinter.
*/
- public final String toString(PrettyPrinterConfiguration prettyPrinterConfiguration) {
- return new PrettyPrinter(prettyPrinterConfiguration).print(this);
+ public final String toString(ConfigurablePrinter configuration) {
+ return getPrinter(configuration).print(this);
}
@Override
@@ -690,14 +725,6 @@
return this;
}
- public static PrettyPrinterConfiguration getToStringPrettyPrinterConfiguration() {
- return toStringPrettyPrinterConfiguration;
- }
-
- public static void setToStringPrettyPrinterConfiguration(PrettyPrinterConfiguration toStringPrettyPrinterConfiguration) {
- Node.toStringPrettyPrinterConfiguration = toStringPrettyPrinterConfiguration;
- }
-
@Generated("com.github.javaparser.generator.core.node.ReplaceMethodGenerator")
public boolean replace(Node node, Node replacementNode) {
if (node == null)
diff --git a/javaparser-core/src/main/java/com/github/javaparser/printer/DefaultPrintableSource.java b/javaparser-core/src/main/java/com/github/javaparser/printer/DefaultPrintableSource.java
new file mode 100755
index 0000000..9bc6118
--- /dev/null
+++ b/javaparser-core/src/main/java/com/github/javaparser/printer/DefaultPrintableSource.java
@@ -0,0 +1,272 @@
+/*
+ * Copyright (C) 2011, 2013-2020 The JavaParser Team.
+ *
+ * This file is part of JavaParser.
+ *
+ * JavaParser can be used either under the terms of
+ * a) the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ * b) the terms of the Apache License
+ *
+ * You should have received a copy of both licenses in LICENCE.LGPL and
+ * LICENCE.APACHE. Please refer to those files for details.
+ *
+ * JavaParser is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ */
+
+package com.github.javaparser.printer;
+
+import static com.github.javaparser.printer.configuration.Indentation.IndentType.SPACES;
+
+import java.util.Deque;
+import java.util.LinkedList;
+
+import com.github.javaparser.Position;
+import com.github.javaparser.printer.configuration.ConfigurablePrinter;
+import com.github.javaparser.printer.configuration.Indentation;
+import com.github.javaparser.printer.configuration.Indentation.IndentType;
+import com.github.javaparser.printer.configuration.PrinterConfiguration.ConfigOption;
+import com.github.javaparser.utils.Utils;
+
+/**
+ * A support class for code that outputs formatted source code.
+ */
+public class DefaultPrintableSource implements PrintableSource {
+ private final String endOfLineCharacter;
+ private final Indentation indentation;
+
+ private final Deque<String> indents = new LinkedList<>();
+ private final Deque<String> reindentedIndents = new LinkedList<>();
+ private String lastPrintedIndent = "";
+ private StringBuilder buf = new StringBuilder();
+ private Position cursor = new Position(Position.FIRST_LINE, Position.FIRST_COLUMN - 1); // Start before the first column
+ private boolean indented = false;
+
+ public DefaultPrintableSource(final ConfigurablePrinter configuration) {
+ indentation = configuration.getIndentation();
+ endOfLineCharacter = configuration.get(ConfigOption.END_OF_LINE_CHARACTER).get().asString();
+ indents.push("");
+ }
+
+ /**
+ * Add the default indentation to the current indentation and push it on the indentation stack.
+ * Does not actually output anything.
+ */
+ @Override
+ public PrintableSource indent() {
+ String currentIndent = indents.peek();
+ switch (indentation.getType()) {
+ case SPACES:
+ case TABS_WITH_SPACE_ALIGN:
+ indents.push(currentIndent + indentation.getIndent());
+ break;
+
+ case TABS:
+ indents.push(indentation.getIndent() + currentIndent);
+ break;
+
+ default:
+ throw new AssertionError("Unhandled indent type");
+ }
+ return this;
+ }
+
+ /**
+ * Add to the current indentation until it is reaches "column" and push it on the indentation stack.
+ * Does not actually output anything.
+ */
+ @Override
+ public PrintableSource indentWithAlignTo(int column) {
+ indents.push(calculateIndentWithAlignTo(column));
+ return this;
+ }
+
+ private String calculateIndentWithAlignTo(int column) {
+ if (column < lastPrintedIndent.length()){
+ throw new IllegalStateException("Attempt to indent less than the previous indent.");
+ }
+
+ StringBuilder newIndent = new StringBuilder(lastPrintedIndent);
+ switch (indentation.getType()) {
+ case SPACES:
+ case TABS_WITH_SPACE_ALIGN:
+ while (newIndent.length() < column) {
+ newIndent.append(SPACES.getCar());
+ }
+ break;
+
+ case TABS:
+ IndentType currentIndentType = indentation.getType();
+ int logicalIndentLength = newIndent.length();
+ while ((logicalIndentLength + currentIndentType.getWidth()) <= column) {
+ newIndent.insert(0, currentIndentType.getCar());
+ logicalIndentLength += currentIndentType.getWidth();
+ }
+ while (logicalIndentLength < column) {
+ newIndent.append(SPACES.getCar());
+ logicalIndentLength++;
+ }
+ StringBuilder fullTab = new StringBuilder();
+ for(int i=0; i<currentIndentType.getWidth(); i++){
+ fullTab.append(SPACES.getCar());
+ }
+ String fullTabString = fullTab.toString();
+ if ((newIndent.length() >= currentIndentType.getWidth())
+ && newIndent.substring(newIndent.length() - currentIndentType.getWidth()).equals(fullTabString)) {
+ int i = newIndent.indexOf(fullTabString);
+ newIndent.replace(i, i + currentIndentType.getWidth(), currentIndentType.getCar().toString());
+ }
+ break;
+
+ default:
+ throw new AssertionError("Unhandled indent type");
+ }
+
+ return newIndent.toString();
+ }
+
+ /**
+ * Pop the last indentation of the indentation stack.
+ * Does not actually output anything.
+ */
+ @Override
+ public PrintableSource unindent() {
+ if (indents.isEmpty()) {
+ // Since we start out with an empty indent on the stack, this will only occur
+ // the second time we over-unindent.
+ throw new IllegalStateException("Indent/unindent calls are not well-balanced.");
+ }
+ indents.pop();
+ return this;
+ }
+
+ private void append(String arg) {
+ buf.append(arg);
+ cursor = cursor.withColumn(cursor.column + arg.length());
+ }
+
+ /**
+ * Append the source string passed as argument to the buffer.
+ * If this is being appended at the beginning of a line, performs indentation first.
+ * <p>
+ * The source line to be printed should not contain newline/carriage-return characters;
+ * use {@link #println(String)} to automatically append a newline at the end of the source string.
+ * If the source line passed as argument contains newline/carriage-return characters would
+ * impredictably affect a correct computation of the current {@link #getCursor()} position.
+ *
+ * @param arg source line to be printed (should not contain newline/carriage-return characters)
+ * @return this instance, for nesting calls to method as fluent interface
+ * @see DefaultPrintableSource#println(String)
+ */
+ @Override
+ public PrintableSource print(final String arg) {
+ if (!indented) {
+ lastPrintedIndent = indents.peek();
+ append(lastPrintedIndent);
+ indented = true;
+ }
+ append(arg);
+ return this;
+ }
+
+ /**
+ * Append the source string passed as argument to the buffer, then append a newline.
+ * If this is being appended at the beginning of a line, performs indentation first.
+ * <p>
+ * The source line to be printed should not contain newline/carriage-return characters.
+ * If the source line passed as argument contains newline/carriage-return characters would
+ * impredictably affect a correct computation of the current {@link #getCursor()} position.
+ *
+ * @param arg source line to be printed (should not contain newline/carriage-return characters)
+ * @return this instance, for nesting calls to method as fluent interface
+ */
+ @Override
+ public PrintableSource println(final String arg) {
+ print(arg);
+ println();
+ return this;
+ }
+
+ /**
+ * Append a newline to the buffer.
+ *
+ * @return this instance, for nesting calls to method as fluent interface
+ */
+ @Override
+ public PrintableSource println() {
+ buf.append(endOfLineCharacter);
+ cursor = new Position(cursor.line + 1, Position.FIRST_COLUMN - 1); // Start before the first column
+ indented = false;
+ return this;
+ }
+
+ /**
+ * Return the current cursor position (line, column) in the source printer buffer.
+ * <p>
+ * Please notice in order to guarantee a correct computation of the cursor position,
+ * this printer expect the contracts of the methods {@link #print(String)} and {@link #println(String)}
+ * has been respected through all method calls, meaning the source string passed as argument to those method
+ * calls did not contain newline/carriage-return characters.
+ *
+ * @return the current cursor position (line, column).
+ */
+ @Override
+ public Position getCursor() {
+ return cursor;
+ }
+
+ /**
+ * @return the currently printed source code.
+ */
+ @Override
+ public String toString() {
+ return buf.toString();
+ }
+
+ /**
+ * Changes all EOL characters in "content" to the EOL character this SourcePrinter is using.
+ */
+ @Override
+ public String normalizeEolInTextBlock(String content) {
+ return Utils.normalizeEolInTextBlock(content, endOfLineCharacter);
+ }
+
+ /**
+ * Set the top-most indent to the column the cursor is currently in, can be undone with
+ * {@link #reindentToPreviousLevel()}. Does not actually output anything.
+ */
+ @Override
+ public void reindentWithAlignToCursor() {
+ String newIndent = calculateIndentWithAlignTo(cursor.column);
+ reindentedIndents.push(indents.pop());
+ indents.push(newIndent);
+ }
+
+ /**
+ * Set the top-most indent to the column the cursor was before the last {@link #reindentWithAlignToCursor()} call.
+ * Does not actually output anything.
+ */
+ @Override
+ public void reindentToPreviousLevel() {
+ if (reindentedIndents.isEmpty()) {
+ throw new IllegalStateException("Reindent calls are not well-balanced.");
+ }
+ indents.pop();
+ indents.push(reindentedIndents.pop());
+ }
+
+ /**
+ * Adds an indent to the top of the stack that is a copy of the current top indent.
+ * With this you announce "I'm going to indent the next line(s)" but not how far yet.
+ * Once you do know, you can pop this indent ("unindent") and indent to the right column.
+ * (Does not actually output anything.)
+ */
+ @Override
+ public void duplicateIndent() {
+ indents.push(indents.peek());
+ }
+}
diff --git a/javaparser-core/src/main/java/com/github/javaparser/printer/PrettyPrintVisitor.java b/javaparser-core/src/main/java/com/github/javaparser/printer/PrettyPrintVisitor.java
index a9b4ec5..d179f20 100644
--- a/javaparser-core/src/main/java/com/github/javaparser/printer/PrettyPrintVisitor.java
+++ b/javaparser-core/src/main/java/com/github/javaparser/printer/PrettyPrintVisitor.java
@@ -62,7 +62,45 @@
import com.github.javaparser.ast.comments.Comment;
import com.github.javaparser.ast.comments.JavadocComment;
import com.github.javaparser.ast.comments.LineComment;
-import com.github.javaparser.ast.expr.*;
+import com.github.javaparser.ast.expr.AnnotationExpr;
+import com.github.javaparser.ast.expr.ArrayAccessExpr;
+import com.github.javaparser.ast.expr.ArrayCreationExpr;
+import com.github.javaparser.ast.expr.ArrayInitializerExpr;
+import com.github.javaparser.ast.expr.AssignExpr;
+import com.github.javaparser.ast.expr.BinaryExpr;
+import com.github.javaparser.ast.expr.BooleanLiteralExpr;
+import com.github.javaparser.ast.expr.CastExpr;
+import com.github.javaparser.ast.expr.CharLiteralExpr;
+import com.github.javaparser.ast.expr.ClassExpr;
+import com.github.javaparser.ast.expr.ConditionalExpr;
+import com.github.javaparser.ast.expr.DoubleLiteralExpr;
+import com.github.javaparser.ast.expr.EnclosedExpr;
+import com.github.javaparser.ast.expr.Expression;
+import com.github.javaparser.ast.expr.FieldAccessExpr;
+import com.github.javaparser.ast.expr.InstanceOfExpr;
+import com.github.javaparser.ast.expr.IntegerLiteralExpr;
+import com.github.javaparser.ast.expr.LambdaExpr;
+import com.github.javaparser.ast.expr.LongLiteralExpr;
+import com.github.javaparser.ast.expr.MarkerAnnotationExpr;
+import com.github.javaparser.ast.expr.MemberValuePair;
+import com.github.javaparser.ast.expr.MethodCallExpr;
+import com.github.javaparser.ast.expr.MethodReferenceExpr;
+import com.github.javaparser.ast.expr.Name;
+import com.github.javaparser.ast.expr.NameExpr;
+import com.github.javaparser.ast.expr.NormalAnnotationExpr;
+import com.github.javaparser.ast.expr.NullLiteralExpr;
+import com.github.javaparser.ast.expr.ObjectCreationExpr;
+import com.github.javaparser.ast.expr.PatternExpr;
+import com.github.javaparser.ast.expr.SimpleName;
+import com.github.javaparser.ast.expr.SingleMemberAnnotationExpr;
+import com.github.javaparser.ast.expr.StringLiteralExpr;
+import com.github.javaparser.ast.expr.SuperExpr;
+import com.github.javaparser.ast.expr.SwitchExpr;
+import com.github.javaparser.ast.expr.TextBlockLiteralExpr;
+import com.github.javaparser.ast.expr.ThisExpr;
+import com.github.javaparser.ast.expr.TypeExpr;
+import com.github.javaparser.ast.expr.UnaryExpr;
+import com.github.javaparser.ast.expr.VariableDeclarationExpr;
import com.github.javaparser.ast.modules.ModuleDeclaration;
import com.github.javaparser.ast.modules.ModuleExportsDirective;
import com.github.javaparser.ast.modules.ModuleOpensDirective;
@@ -112,20 +150,29 @@
import com.github.javaparser.ast.type.WildcardType;
import com.github.javaparser.ast.visitor.Visitable;
import com.github.javaparser.ast.visitor.VoidVisitor;
+import com.github.javaparser.printer.configuration.PrettyPrinterConfiguration;
/**
* Outputs the AST as formatted Java source code.
- *
+ * This class is no longer acceptable to use because it is not sufficiently configurable and it is too tied to a specific implementation
+ * <p> Use {@link PrintableVisitor default implementation } instead.
* @author Julio Vilmar Gesser
+ * This class is no longer acceptable to use because it is not sufficiently configurable and it is too tied to a specific implementation
+ * <p> Use {@link PrintableVisitor default implementation } instead.
*/
+@Deprecated
public class PrettyPrintVisitor implements VoidVisitor<Void> {
- protected final PrettyPrinterConfiguration configuration;
+ protected PrettyPrinterConfiguration configuration;
protected final SourcePrinter printer;
public PrettyPrintVisitor(PrettyPrinterConfiguration prettyPrinterConfiguration) {
- configuration = prettyPrinterConfiguration;
+ this.configuration = prettyPrinterConfiguration;
printer = new SourcePrinter(configuration);
}
+
+ public void setConfiguration(PrettyPrinterConfiguration prettyPrinterConfiguration) {
+ this.configuration = prettyPrinterConfiguration;
+ }
/**
* @deprecated use toString()
diff --git a/javaparser-core/src/main/java/com/github/javaparser/printer/PrettyPrintable.java b/javaparser-core/src/main/java/com/github/javaparser/printer/PrettyPrintable.java
new file mode 100755
index 0000000..fe5e75f
--- /dev/null
+++ b/javaparser-core/src/main/java/com/github/javaparser/printer/PrettyPrintable.java
@@ -0,0 +1,107 @@
+/*
+ * Copyright (C) 2007-2010 Júlio Vilmar Gesser.
+ * Copyright (C) 2011, 2013-2020 The JavaParser Team.
+ *
+ * This file is part of JavaParser.
+ *
+ * JavaParser can be used either under the terms of
+ * a) the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ * b) the terms of the Apache License
+ *
+ * You should have received a copy of both licenses in LICENCE.LGPL and
+ * LICENCE.APACHE. Please refer to those files for details.
+ *
+ * JavaParser is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ */
+
+package com.github.javaparser.printer;
+
+import java.util.function.Function;
+
+import com.github.javaparser.ast.Node;
+import com.github.javaparser.ast.visitor.VoidVisitor;
+import com.github.javaparser.printer.configuration.ConfigurablePrinter;
+import com.github.javaparser.printer.configuration.PrinterConfiguration;
+
+/**
+ * Pretty printer for AST nodes.
+ */
+public class PrettyPrintable implements Printable {
+
+ private ConfigurablePrinter configuration;
+
+ // visitor factory
+ Function<ConfigurablePrinter, VoidVisitor<Void>> visitorFactory;
+
+ // static methods
+
+ private static Function<ConfigurablePrinter, VoidVisitor<Void>> createDefaultVisitor() {
+ ConfigurablePrinter configuration = createDefaultConfiguration();
+ return createDefaultVisitor(configuration);
+ }
+
+ private static Function<ConfigurablePrinter, VoidVisitor<Void>> createDefaultVisitor(ConfigurablePrinter configuration) {
+ return (config) -> new PrintableVisitor(config, new DefaultPrintableSource(config));
+ }
+
+ private static ConfigurablePrinter createDefaultConfiguration() {
+ return new PrinterConfiguration();
+ }
+
+ // Constructors
+
+ /**
+ * Build a new PrettyPrintable with a default configuration and a default factory
+ */
+ public PrettyPrintable() {
+ this(createDefaultVisitor(), createDefaultConfiguration() );
+ }
+
+ /**
+ * Build a new PrettyPrintable with a configuration and a default factory
+ * @param configuration
+ */
+ public PrettyPrintable(ConfigurablePrinter configuration) {
+ this(createDefaultVisitor(configuration), configuration );
+ }
+
+ /**
+ * Build a new PrettyPrintable with a configuration and a factory to create a visitor to browse the nodes of the AST
+ * @param visitorFactory
+ * @param configuration Configuration to apply
+ */
+ public PrettyPrintable(Function<ConfigurablePrinter, VoidVisitor<Void>> visitorFactory, ConfigurablePrinter configuration) {
+ this.configuration = configuration;
+ this.visitorFactory = visitorFactory;
+ }
+
+ // Methods
+
+ /*
+ * Returns the Printer configuration
+ */
+ public ConfigurablePrinter getConfiguration() {
+ return configuration;
+ }
+
+ /*
+ * set or update the PrettyPrinter configuration
+ */
+ public Printable setConfiguration(ConfigurablePrinter configuration) {
+ this.configuration = configuration;
+ return this;
+ }
+
+ @Override
+ public String print(Node node) {
+ // lazy initialization of visitor which can have a state (like a buffer)
+ VoidVisitor<Void> visitor = visitorFactory.apply(configuration);
+ node.accept(visitor, null);
+ return visitor.toString();
+ }
+}
diff --git a/javaparser-core/src/main/java/com/github/javaparser/printer/PrettyPrinter.java b/javaparser-core/src/main/java/com/github/javaparser/printer/PrettyPrinter.java
index f79217f..28300a1 100644
--- a/javaparser-core/src/main/java/com/github/javaparser/printer/PrettyPrinter.java
+++ b/javaparser-core/src/main/java/com/github/javaparser/printer/PrettyPrinter.java
@@ -21,41 +21,60 @@
package com.github.javaparser.printer;
+import java.util.function.Function;
+
import com.github.javaparser.ast.Node;
import com.github.javaparser.ast.visitor.VoidVisitor;
+import com.github.javaparser.printer.configuration.ConfigurablePrinter;
+import com.github.javaparser.printer.configuration.PrettyPrinterConfiguration;
/**
* Pretty printer for AST nodes.
+ * This class is no longer acceptable to use because it is not sufficiently configurable and it is too tied to a specific implementation
+ * <p> Use {@link Printable interface or PrettyPrintable default implementation } instead.
*/
+@Deprecated
public class PrettyPrinter implements Printable {
- private PrettyPrinterConfiguration configuration;
+
+ private ConfigurablePrinter configuration;
+
+ private Function<PrettyPrinterConfiguration, VoidVisitor<Void>> visitorFactory;
public PrettyPrinter() {
this(new PrettyPrinterConfiguration());
}
-
+
public PrettyPrinter(PrettyPrinterConfiguration configuration) {
- this.configuration = configuration;
+ this(configuration, PrettyPrintVisitor::new);
}
-
+
+ public PrettyPrinter(PrettyPrinterConfiguration configuration, Function<PrettyPrinterConfiguration, VoidVisitor<Void>> visitorFactory) {
+ this.configuration = configuration;
+ this.visitorFactory = visitorFactory;
+ }
+
/*
* Returns the PrettyPrinter configuration
*/
- public PrettyPrinterConfiguration getConfiguration() {
+ public ConfigurablePrinter getConfiguration() {
return configuration;
}
/*
* set or update the PrettyPrinter configuration
*/
- public void setConfiguration(PrettyPrinterConfiguration configuration) {
+ public Printable setConfiguration(ConfigurablePrinter configuration) {
+ if (!(configuration instanceof PrettyPrinterConfiguration))
+ throw new IllegalArgumentException("PrettyPrinter must be configured with a PrettyPrinterConfiguration class");
this.configuration = configuration;
+ return this;
}
@Override
public String print(Node node) {
- final VoidVisitor<Void> visitor = configuration.getVisitorFactory().apply(configuration);
+ final VoidVisitor<Void> visitor = visitorFactory.apply((PrettyPrinterConfiguration)configuration);
node.accept(visitor, null);
return visitor.toString();
}
+
}
diff --git a/javaparser-core/src/main/java/com/github/javaparser/printer/Printable.java b/javaparser-core/src/main/java/com/github/javaparser/printer/Printable.java
index 660a178..c8a9fab 100755
--- a/javaparser-core/src/main/java/com/github/javaparser/printer/Printable.java
+++ b/javaparser-core/src/main/java/com/github/javaparser/printer/Printable.java
@@ -1,9 +1,14 @@
package com.github.javaparser.printer;
import com.github.javaparser.ast.Node;
+import com.github.javaparser.printer.configuration.ConfigurablePrinter;
public interface Printable {
String print(Node node);
+ Printable setConfiguration(ConfigurablePrinter configuration);
+
+ ConfigurablePrinter getConfiguration();
+
}
\ No newline at end of file
diff --git a/javaparser-core/src/main/java/com/github/javaparser/printer/PrintableSource.java b/javaparser-core/src/main/java/com/github/javaparser/printer/PrintableSource.java
new file mode 100755
index 0000000..547ee27
--- /dev/null
+++ b/javaparser-core/src/main/java/com/github/javaparser/printer/PrintableSource.java
@@ -0,0 +1,122 @@
+/*
+ * Copyright (C) 2011, 2013-2020 The JavaParser Team.
+ *
+ * This file is part of JavaParser.
+ *
+ * JavaParser can be used either under the terms of
+ * a) the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ * b) the terms of the Apache License
+ *
+ * You should have received a copy of both licenses in LICENCE.LGPL and
+ * LICENCE.APACHE. Please refer to those files for details.
+ *
+ * JavaParser is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ */
+
+package com.github.javaparser.printer;
+
+import com.github.javaparser.Position;
+
+public interface PrintableSource {
+
+ /**
+ * Add the default indentation to the current indentation and push it on the indentation stack.
+ * Does not actually output anything.
+ */
+ PrintableSource indent();
+
+ /**
+ * Add to the current indentation until it is reaches "column" and push it on the indentation stack.
+ * Does not actually output anything.
+ */
+ PrintableSource indentWithAlignTo(int column);
+
+ /**
+ * Pop the last indentation of the indentation stack.
+ * Does not actually output anything.
+ */
+ PrintableSource unindent();
+
+ /**
+ * Append the source string passed as argument to the buffer.
+ * If this is being appended at the beginning of a line, performs indentation first.
+ * <p>
+ * The source line to be printed should not contain newline/carriage-return characters;
+ * use {@link #println(String)} to automatically append a newline at the end of the source string.
+ * If the source line passed as argument contains newline/carriage-return characters would
+ * impredictably affect a correct computation of the current {@link #getCursor()} position.
+ *
+ * @param arg source line to be printed (should not contain newline/carriage-return characters)
+ * @return this instance, for nesting calls to method as fluent interface
+ * @see PrintableSource#println(String)
+ */
+ PrintableSource print(String arg);
+
+ /**
+ * Append the source string passed as argument to the buffer, then append a newline.
+ * If this is being appended at the beginning of a line, performs indentation first.
+ * <p>
+ * The source line to be printed should not contain newline/carriage-return characters.
+ * If the source line passed as argument contains newline/carriage-return characters would
+ * impredictably affect a correct computation of the current {@link #getCursor()} position.
+ *
+ * @param arg source line to be printed (should not contain newline/carriage-return characters)
+ * @return this instance, for nesting calls to method as fluent interface
+ */
+ PrintableSource println(String arg);
+
+ /**
+ * Append a newline to the buffer.
+ *
+ * @return this instance, for nesting calls to method as fluent interface
+ */
+ PrintableSource println();
+
+ /**
+ * Return the current cursor position (line, column) in the source printer buffer.
+ * <p>
+ * Please notice in order to guarantee a correct computation of the cursor position,
+ * this printer expect the contracts of the methods {@link #print(String)} and {@link #println(String)}
+ * has been respected through all method calls, meaning the source string passed as argument to those method
+ * calls did not contain newline/carriage-return characters.
+ *
+ * @return the current cursor position (line, column).
+ */
+ Position getCursor();
+
+ /**
+ * @return the currently printed source code.
+ */
+ String toString();
+
+ /**
+ * Changes all EOL characters in "content" to the EOL character this SourcePrinter is using.
+ */
+ String normalizeEolInTextBlock(String content);
+
+ /**
+ * Set the top-most indent to the column the cursor is currently in, can be undone with
+ * {@link #reindentToPreviousLevel()}. Does not actually output anything.
+ */
+ void reindentWithAlignToCursor();
+
+ /**
+ * Set the top-most indent to the column the cursor was before the last {@link #reindentWithAlignToCursor()} call.
+ * Does not actually output anything.
+ */
+ void reindentToPreviousLevel();
+
+ /**
+ * Adds an indent to the top of the stack that is a copy of the current top indent.
+ * With this you announce "I'm going to indent the next line(s)" but not how far yet.
+ * Once you do know, you can pop this indent ("unindent") and indent to the right column.
+ * (Does not actually output anything.)
+ */
+ void duplicateIndent();
+
+}
\ No newline at end of file
diff --git a/javaparser-core/src/main/java/com/github/javaparser/printer/PrintableVisitor.java b/javaparser-core/src/main/java/com/github/javaparser/printer/PrintableVisitor.java
new file mode 100755
index 0000000..8ce3869
--- /dev/null
+++ b/javaparser-core/src/main/java/com/github/javaparser/printer/PrintableVisitor.java
@@ -0,0 +1,1944 @@
+/*
+ * Copyright (C) 2011, 2013-2020 The JavaParser Team.
+ *
+ * This file is part of JavaParser.
+ *
+ * JavaParser can be used either under the terms of
+ * a) the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ * b) the terms of the Apache License
+ *
+ * You should have received a copy of both licenses in LICENCE.LGPL and
+ * LICENCE.APACHE. Please refer to those files for details.
+ *
+ * JavaParser is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ */
+
+package com.github.javaparser.printer;
+
+import static com.github.javaparser.ast.Node.Parsedness.UNPARSABLE;
+import static com.github.javaparser.utils.PositionUtils.sortByBeginPosition;
+import static com.github.javaparser.utils.Utils.isNullOrEmpty;
+import static com.github.javaparser.utils.Utils.normalizeEolInTextBlock;
+import static com.github.javaparser.utils.Utils.trimTrailingSpaces;
+import static java.util.Comparator.comparingInt;
+import static java.util.stream.Collectors.joining;
+
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Optional;
+import java.util.concurrent.atomic.AtomicBoolean;
+import java.util.stream.Collectors;
+
+import com.github.javaparser.ast.ArrayCreationLevel;
+import com.github.javaparser.ast.CompilationUnit;
+import com.github.javaparser.ast.ImportDeclaration;
+import com.github.javaparser.ast.Modifier;
+import com.github.javaparser.ast.Node;
+import com.github.javaparser.ast.NodeList;
+import com.github.javaparser.ast.PackageDeclaration;
+import com.github.javaparser.ast.body.AnnotationDeclaration;
+import com.github.javaparser.ast.body.AnnotationMemberDeclaration;
+import com.github.javaparser.ast.body.BodyDeclaration;
+import com.github.javaparser.ast.body.ClassOrInterfaceDeclaration;
+import com.github.javaparser.ast.body.ConstructorDeclaration;
+import com.github.javaparser.ast.body.EnumConstantDeclaration;
+import com.github.javaparser.ast.body.EnumDeclaration;
+import com.github.javaparser.ast.body.FieldDeclaration;
+import com.github.javaparser.ast.body.InitializerDeclaration;
+import com.github.javaparser.ast.body.MethodDeclaration;
+import com.github.javaparser.ast.body.Parameter;
+import com.github.javaparser.ast.body.ReceiverParameter;
+import com.github.javaparser.ast.body.TypeDeclaration;
+import com.github.javaparser.ast.body.VariableDeclarator;
+import com.github.javaparser.ast.comments.BlockComment;
+import com.github.javaparser.ast.comments.Comment;
+import com.github.javaparser.ast.comments.JavadocComment;
+import com.github.javaparser.ast.comments.LineComment;
+import com.github.javaparser.ast.expr.AnnotationExpr;
+import com.github.javaparser.ast.expr.ArrayAccessExpr;
+import com.github.javaparser.ast.expr.ArrayCreationExpr;
+import com.github.javaparser.ast.expr.ArrayInitializerExpr;
+import com.github.javaparser.ast.expr.AssignExpr;
+import com.github.javaparser.ast.expr.BinaryExpr;
+import com.github.javaparser.ast.expr.BooleanLiteralExpr;
+import com.github.javaparser.ast.expr.CastExpr;
+import com.github.javaparser.ast.expr.CharLiteralExpr;
+import com.github.javaparser.ast.expr.ClassExpr;
+import com.github.javaparser.ast.expr.ConditionalExpr;
+import com.github.javaparser.ast.expr.DoubleLiteralExpr;
+import com.github.javaparser.ast.expr.EnclosedExpr;
+import com.github.javaparser.ast.expr.Expression;
+import com.github.javaparser.ast.expr.FieldAccessExpr;
+import com.github.javaparser.ast.expr.InstanceOfExpr;
+import com.github.javaparser.ast.expr.IntegerLiteralExpr;
+import com.github.javaparser.ast.expr.LambdaExpr;
+import com.github.javaparser.ast.expr.LongLiteralExpr;
+import com.github.javaparser.ast.expr.MarkerAnnotationExpr;
+import com.github.javaparser.ast.expr.MemberValuePair;
+import com.github.javaparser.ast.expr.MethodCallExpr;
+import com.github.javaparser.ast.expr.MethodReferenceExpr;
+import com.github.javaparser.ast.expr.Name;
+import com.github.javaparser.ast.expr.NameExpr;
+import com.github.javaparser.ast.expr.NormalAnnotationExpr;
+import com.github.javaparser.ast.expr.NullLiteralExpr;
+import com.github.javaparser.ast.expr.ObjectCreationExpr;
+import com.github.javaparser.ast.expr.PatternExpr;
+import com.github.javaparser.ast.expr.SimpleName;
+import com.github.javaparser.ast.expr.SingleMemberAnnotationExpr;
+import com.github.javaparser.ast.expr.StringLiteralExpr;
+import com.github.javaparser.ast.expr.SuperExpr;
+import com.github.javaparser.ast.expr.SwitchExpr;
+import com.github.javaparser.ast.expr.TextBlockLiteralExpr;
+import com.github.javaparser.ast.expr.ThisExpr;
+import com.github.javaparser.ast.expr.TypeExpr;
+import com.github.javaparser.ast.expr.UnaryExpr;
+import com.github.javaparser.ast.expr.VariableDeclarationExpr;
+import com.github.javaparser.ast.modules.ModuleDeclaration;
+import com.github.javaparser.ast.modules.ModuleExportsDirective;
+import com.github.javaparser.ast.modules.ModuleOpensDirective;
+import com.github.javaparser.ast.modules.ModuleProvidesDirective;
+import com.github.javaparser.ast.modules.ModuleRequiresDirective;
+import com.github.javaparser.ast.modules.ModuleUsesDirective;
+import com.github.javaparser.ast.nodeTypes.NodeWithName;
+import com.github.javaparser.ast.nodeTypes.NodeWithTraversableScope;
+import com.github.javaparser.ast.nodeTypes.NodeWithTypeArguments;
+import com.github.javaparser.ast.nodeTypes.NodeWithVariables;
+import com.github.javaparser.ast.nodeTypes.SwitchNode;
+import com.github.javaparser.ast.stmt.AssertStmt;
+import com.github.javaparser.ast.stmt.BlockStmt;
+import com.github.javaparser.ast.stmt.BreakStmt;
+import com.github.javaparser.ast.stmt.CatchClause;
+import com.github.javaparser.ast.stmt.ContinueStmt;
+import com.github.javaparser.ast.stmt.DoStmt;
+import com.github.javaparser.ast.stmt.EmptyStmt;
+import com.github.javaparser.ast.stmt.ExplicitConstructorInvocationStmt;
+import com.github.javaparser.ast.stmt.ExpressionStmt;
+import com.github.javaparser.ast.stmt.ForEachStmt;
+import com.github.javaparser.ast.stmt.ForStmt;
+import com.github.javaparser.ast.stmt.IfStmt;
+import com.github.javaparser.ast.stmt.LabeledStmt;
+import com.github.javaparser.ast.stmt.LocalClassDeclarationStmt;
+import com.github.javaparser.ast.stmt.ReturnStmt;
+import com.github.javaparser.ast.stmt.Statement;
+import com.github.javaparser.ast.stmt.SwitchEntry;
+import com.github.javaparser.ast.stmt.SwitchStmt;
+import com.github.javaparser.ast.stmt.SynchronizedStmt;
+import com.github.javaparser.ast.stmt.ThrowStmt;
+import com.github.javaparser.ast.stmt.TryStmt;
+import com.github.javaparser.ast.stmt.UnparsableStmt;
+import com.github.javaparser.ast.stmt.WhileStmt;
+import com.github.javaparser.ast.stmt.YieldStmt;
+import com.github.javaparser.ast.type.ArrayType;
+import com.github.javaparser.ast.type.ClassOrInterfaceType;
+import com.github.javaparser.ast.type.IntersectionType;
+import com.github.javaparser.ast.type.PrimitiveType;
+import com.github.javaparser.ast.type.ReferenceType;
+import com.github.javaparser.ast.type.Type;
+import com.github.javaparser.ast.type.TypeParameter;
+import com.github.javaparser.ast.type.UnionType;
+import com.github.javaparser.ast.type.UnknownType;
+import com.github.javaparser.ast.type.VarType;
+import com.github.javaparser.ast.type.VoidType;
+import com.github.javaparser.ast.type.WildcardType;
+import com.github.javaparser.ast.visitor.Visitable;
+import com.github.javaparser.ast.visitor.VoidVisitor;
+import com.github.javaparser.printer.configuration.ConfigurablePrinter;
+import com.github.javaparser.printer.configuration.PrinterConfiguration.ConfigOption;
+
+/**
+ * Outputs the AST as formatted Java source code.
+ *
+ */
+public class PrintableVisitor implements VoidVisitor<Void> {
+ protected final ConfigurablePrinter configuration;
+ protected final PrintableSource printer;
+
+ public PrintableVisitor(ConfigurablePrinter configuration) {
+ this(configuration, new DefaultPrintableSource(configuration));
+ }
+
+ public PrintableVisitor(ConfigurablePrinter configuration, PrintableSource printer) {
+ this.configuration = configuration;
+ this.printer = printer;
+ }
+
+ @Override
+ public String toString() {
+ return printer.toString();
+ }
+
+ protected void printModifiers(final NodeList<Modifier> modifiers) {
+ if (modifiers.size() > 0) {
+ printer.print(modifiers.stream().map(Modifier::getKeyword).map(Modifier.Keyword::asString).collect(joining(" ")) + " ");
+ }
+ }
+
+ protected void printMembers(final NodeList<BodyDeclaration<?>> members, final Void arg) {
+ for (final BodyDeclaration<?> member : members) {
+ printer.println();
+ member.accept(this, arg);
+ printer.println();
+ }
+ }
+
+ protected void printMemberAnnotations(final NodeList<AnnotationExpr> annotations, final Void arg) {
+ if (annotations.isEmpty()) {
+ return;
+ }
+ for (final AnnotationExpr a : annotations) {
+ a.accept(this, arg);
+ printer.println();
+ }
+ }
+
+ protected void printAnnotations(final NodeList<AnnotationExpr> annotations, boolean prefixWithASpace,
+ final Void arg) {
+ if (annotations.isEmpty()) {
+ return;
+ }
+ if (prefixWithASpace) {
+ printer.print(" ");
+ }
+ for (AnnotationExpr annotation : annotations) {
+ annotation.accept(this, arg);
+ printer.print(" ");
+ }
+ }
+
+ protected void printTypeArgs(final NodeWithTypeArguments<?> nodeWithTypeArguments, final Void arg) {
+ NodeList<Type> typeArguments = nodeWithTypeArguments.getTypeArguments().orElse(null);
+ if (!isNullOrEmpty(typeArguments)) {
+ printer.print("<");
+ for (final Iterator<Type> i = typeArguments.iterator(); i.hasNext(); ) {
+ final Type t = i.next();
+ t.accept(this, arg);
+ if (i.hasNext()) {
+ printer.print(", ");
+ }
+ }
+ printer.print(">");
+ }
+ }
+
+ protected void printTypeParameters(final NodeList<TypeParameter> args, final Void arg) {
+ if (!isNullOrEmpty(args)) {
+ printer.print("<");
+ for (final Iterator<TypeParameter> i = args.iterator(); i.hasNext(); ) {
+ final TypeParameter t = i.next();
+ t.accept(this, arg);
+ if (i.hasNext()) {
+ printer.print(", ");
+ }
+ }
+ printer.print(">");
+ }
+ }
+
+ protected void printArguments(final NodeList<Expression> args, final Void arg) {
+ printer.print("(");
+ if (!isNullOrEmpty(args)) {
+ boolean columnAlignParameters = (args.size() > 1) && configuration.get(ConfigOption.COLUMN_ALIGN_PARAMETERS).isPresent();
+ if (columnAlignParameters) {
+ printer.indentWithAlignTo(printer.getCursor().column);
+ }
+ for (final Iterator<Expression> i = args.iterator(); i.hasNext(); ) {
+ final Expression e = i.next();
+ e.accept(this, arg);
+ if (i.hasNext()) {
+ printer.print(",");
+ if (columnAlignParameters) {
+ printer.println();
+ } else {
+ printer.print(" ");
+ }
+ }
+ }
+ if (columnAlignParameters) {
+ printer.unindent();
+ }
+ }
+ printer.print(")");
+ }
+
+ protected void printPrePostFixOptionalList(final NodeList<? extends Visitable> args, final Void arg, String prefix, String separator, String postfix) {
+ if (!args.isEmpty()) {
+ printer.print(prefix);
+ for (final Iterator<? extends Visitable> i = args.iterator(); i.hasNext(); ) {
+ final Visitable v = i.next();
+ v.accept(this, arg);
+ if (i.hasNext()) {
+ printer.print(separator);
+ }
+ }
+ printer.print(postfix);
+ }
+ }
+
+ protected void printPrePostFixRequiredList(final NodeList<? extends Visitable> args, final Void arg, String prefix, String separator, String postfix) {
+ printer.print(prefix);
+ if (!args.isEmpty()) {
+ for (final Iterator<? extends Visitable> i = args.iterator(); i.hasNext(); ) {
+ final Visitable v = i.next();
+ v.accept(this, arg);
+ if (i.hasNext()) {
+ printer.print(separator);
+ }
+ }
+ }
+ printer.print(postfix);
+ }
+
+ protected void printComment(final Optional<Comment> comment, final Void arg) {
+ comment.ifPresent(c -> c.accept(this, arg));
+ }
+
+ @Override
+ public void visit(final CompilationUnit n, final Void arg) {
+ printOrphanCommentsBeforeThisChildNode(n);
+ printComment(n.getComment(), arg);
+ if (n.getParsed() == UNPARSABLE) {
+ printer.println("???");
+ return;
+ }
+
+ if (n.getPackageDeclaration().isPresent()) {
+ n.getPackageDeclaration().get().accept(this, arg);
+ }
+
+ n.getImports().accept(this, arg);
+ if (!n.getImports().isEmpty()) {
+ printer.println();
+ }
+
+ for (final Iterator<TypeDeclaration<?>> i = n.getTypes().iterator(); i.hasNext(); ) {
+ i.next().accept(this, arg);
+ printer.println();
+ if (i.hasNext()) {
+ printer.println();
+ }
+ }
+
+ n.getModule().ifPresent(m -> m.accept(this, arg));
+
+ printOrphanCommentsEnding(n);
+ }
+
+ @Override
+ public void visit(final PackageDeclaration n, final Void arg) {
+ printOrphanCommentsBeforeThisChildNode(n);
+ printComment(n.getComment(), arg);
+ printMemberAnnotations(n.getAnnotations(), arg);
+ printer.print("package ");
+ n.getName().accept(this, arg);
+ printer.println(";");
+ printer.println();
+
+ printOrphanCommentsEnding(n);
+ }
+
+ @Override
+ public void visit(final NameExpr n, final Void arg) {
+ printOrphanCommentsBeforeThisChildNode(n);
+ printComment(n.getComment(), arg);
+ n.getName().accept(this, arg);
+
+ printOrphanCommentsEnding(n);
+ }
+
+ @Override
+ public void visit(final Name n, final Void arg) {
+ printOrphanCommentsBeforeThisChildNode(n);
+ printComment(n.getComment(), arg);
+ if (n.getQualifier().isPresent()) {
+ n.getQualifier().get().accept(this, arg);
+ printer.print(".");
+ }
+ printer.print(n.getIdentifier());
+
+ printOrphanCommentsEnding(n);
+ }
+
+ @Override
+ public void visit(SimpleName n, Void arg) {
+ printer.print(n.getIdentifier());
+ }
+
+ @Override
+ public void visit(final ClassOrInterfaceDeclaration n, final Void arg) {
+ printOrphanCommentsBeforeThisChildNode(n);
+ printComment(n.getComment(), arg);
+ printMemberAnnotations(n.getAnnotations(), arg);
+ printModifiers(n.getModifiers());
+
+ if (n.isInterface()) {
+ printer.print("interface ");
+ } else {
+ printer.print("class ");
+ }
+
+ n.getName().accept(this, arg);
+
+ printTypeParameters(n.getTypeParameters(), arg);
+
+ if (!n.getExtendedTypes().isEmpty()) {
+ printer.print(" extends ");
+ for (final Iterator<ClassOrInterfaceType> i = n.getExtendedTypes().iterator(); i.hasNext(); ) {
+ final ClassOrInterfaceType c = i.next();
+ c.accept(this, arg);
+ if (i.hasNext()) {
+ printer.print(", ");
+ }
+ }
+ }
+
+ if (!n.getImplementedTypes().isEmpty()) {
+ printer.print(" implements ");
+ for (final Iterator<ClassOrInterfaceType> i = n.getImplementedTypes().iterator(); i.hasNext(); ) {
+ final ClassOrInterfaceType c = i.next();
+ c.accept(this, arg);
+ if (i.hasNext()) {
+ printer.print(", ");
+ }
+ }
+ }
+
+ printer.println(" {");
+ printer.indent();
+ if (!isNullOrEmpty(n.getMembers())) {
+ printMembers(n.getMembers(), arg);
+ }
+
+ printOrphanCommentsEnding(n);
+
+ printer.unindent();
+ printer.print("}");
+ }
+
+ @Override
+ public void visit(final JavadocComment n, final Void arg) {
+ printOrphanCommentsBeforeThisChildNode(n);
+ if (configuration.get(ConfigOption.PRINT_COMMENTS).isPresent() && configuration.get(ConfigOption.PRINT_JAVADOC).isPresent()) {
+ printer.println("/**");
+ final String commentContent = normalizeEolInTextBlock(n.getContent(), configuration.get(ConfigOption.END_OF_LINE_CHARACTER).get().asString());
+ String[] lines = commentContent.split("\\R");
+ List<String> strippedLines = new ArrayList<>();
+ for (String line : lines) {
+ final String trimmedLine = line.trim();
+ if (trimmedLine.startsWith("*")) {
+ line = trimmedLine.substring(1);
+ }
+ line = trimTrailingSpaces(line);
+ strippedLines.add(line);
+ }
+
+ boolean skippingLeadingEmptyLines = true;
+ boolean prependEmptyLine = false;
+ boolean prependSpace = strippedLines.stream().anyMatch(line -> !line.isEmpty() && !line.startsWith(" "));
+ for (String line : strippedLines) {
+ if (line.isEmpty()) {
+ if (!skippingLeadingEmptyLines) {
+ prependEmptyLine = true;
+ }
+ } else {
+ skippingLeadingEmptyLines = false;
+ if (prependEmptyLine) {
+ printer.println(" *");
+ prependEmptyLine = false;
+ }
+ printer.print(" *");
+ if (prependSpace) {
+ printer.print(" ");
+ }
+ printer.println(line);
+ }
+ }
+ printer.println(" */");
+ }
+ }
+
+ @Override
+ public void visit(final ClassOrInterfaceType n, final Void arg) {
+ printOrphanCommentsBeforeThisChildNode(n);
+ printComment(n.getComment(), arg);
+ if (n.getScope().isPresent()) {
+ n.getScope().get().accept(this, arg);
+ printer.print(".");
+ }
+ printAnnotations(n.getAnnotations(), false, arg);
+
+ n.getName().accept(this, arg);
+
+ if (n.isUsingDiamondOperator()) {
+ printer.print("<>");
+ } else {
+ printTypeArgs(n, arg);
+ }
+ }
+
+ @Override
+ public void visit(final TypeParameter n, final Void arg) {
+ printOrphanCommentsBeforeThisChildNode(n);
+ printComment(n.getComment(), arg);
+ printAnnotations(n.getAnnotations(), false, arg);
+ n.getName().accept(this, arg);
+ if (!isNullOrEmpty(n.getTypeBound())) {
+ printer.print(" extends ");
+ for (final Iterator<ClassOrInterfaceType> i = n.getTypeBound().iterator(); i.hasNext(); ) {
+ final ClassOrInterfaceType c = i.next();
+ c.accept(this, arg);
+ if (i.hasNext()) {
+ printer.print(" & ");
+ }
+ }
+ }
+ }
+
+ @Override
+ public void visit(final PrimitiveType n, final Void arg) {
+ printOrphanCommentsBeforeThisChildNode(n);
+ printComment(n.getComment(), arg);
+ printAnnotations(n.getAnnotations(), true, arg);
+ printer.print(n.getType().asString());
+ }
+
+ @Override
+ public void visit(final ArrayType n, final Void arg) {
+ final List<ArrayType> arrayTypeBuffer = new LinkedList<>();
+ Type type = n;
+ while (type instanceof ArrayType) {
+ final ArrayType arrayType = (ArrayType) type;
+ arrayTypeBuffer.add(arrayType);
+ type = arrayType.getComponentType();
+ }
+
+ type.accept(this, arg);
+ for (ArrayType arrayType : arrayTypeBuffer) {
+ printAnnotations(arrayType.getAnnotations(), true, arg);
+ printer.print("[]");
+ }
+ }
+
+ @Override
+ public void visit(final ArrayCreationLevel n, final Void arg) {
+ printAnnotations(n.getAnnotations(), true, arg);
+ printer.print("[");
+ if (n.getDimension().isPresent()) {
+ n.getDimension().get().accept(this, arg);
+ }
+ printer.print("]");
+ }
+
+ @Override
+ public void visit(final IntersectionType n, final Void arg) {
+ printOrphanCommentsBeforeThisChildNode(n);
+ printComment(n.getComment(), arg);
+ printAnnotations(n.getAnnotations(), false, arg);
+ boolean isFirst = true;
+ for (ReferenceType element : n.getElements()) {
+ if (isFirst) {
+ isFirst = false;
+ } else {
+ printer.print(" & ");
+ }
+ element.accept(this, arg);
+ }
+ }
+
+ @Override
+ public void visit(final UnionType n, final Void arg) {
+ printOrphanCommentsBeforeThisChildNode(n);
+ printComment(n.getComment(), arg);
+ printAnnotations(n.getAnnotations(), true, arg);
+ boolean isFirst = true;
+ for (ReferenceType element : n.getElements()) {
+ if (isFirst) {
+ isFirst = false;
+ } else {
+ printer.print(" | ");
+ }
+ element.accept(this, arg);
+ }
+ }
+
+ @Override
+ public void visit(final WildcardType n, final Void arg) {
+ printOrphanCommentsBeforeThisChildNode(n);
+ printComment(n.getComment(), arg);
+ printAnnotations(n.getAnnotations(), false, arg);
+ printer.print("?");
+ if (n.getExtendedType().isPresent()) {
+ printer.print(" extends ");
+ n.getExtendedType().get().accept(this, arg);
+ }
+ if (n.getSuperType().isPresent()) {
+ printer.print(" super ");
+ n.getSuperType().get().accept(this, arg);
+ }
+ }
+
+ @Override
+ public void visit(final UnknownType n, final Void arg) {
+ // Nothing to print
+ }
+
+ @Override
+ public void visit(final FieldDeclaration n, final Void arg) {
+ printOrphanCommentsBeforeThisChildNode(n);
+
+ printComment(n.getComment(), arg);
+ printMemberAnnotations(n.getAnnotations(), arg);
+ printModifiers(n.getModifiers());
+ if (!n.getVariables().isEmpty()) {
+ Optional<Type> maximumCommonType = n.getMaximumCommonType();
+ maximumCommonType.ifPresent(t -> t.accept(this, arg));
+ if (!maximumCommonType.isPresent()) {
+ printer.print("???");
+ }
+ }
+
+ printer.print(" ");
+ for (final Iterator<VariableDeclarator> i = n.getVariables().iterator(); i.hasNext(); ) {
+ final VariableDeclarator var = i.next();
+ var.accept(this, arg);
+ if (i.hasNext()) {
+ printer.print(", ");
+ }
+ }
+
+ printer.print(";");
+ }
+
+ @Override
+ public void visit(final VariableDeclarator n, final Void arg) {
+ printOrphanCommentsBeforeThisChildNode(n);
+ printComment(n.getComment(), arg);
+ n.getName().accept(this, arg);
+
+ n.findAncestor(NodeWithVariables.class).ifPresent(ancestor -> ((NodeWithVariables<?>) ancestor).getMaximumCommonType().ifPresent(commonType -> {
+
+ final Type type = n.getType();
+
+ ArrayType arrayType = null;
+
+ for (int i = commonType.getArrayLevel(); i < type.getArrayLevel(); i++) {
+ if (arrayType == null) {
+ arrayType = (ArrayType) type;
+ } else {
+ arrayType = (ArrayType) arrayType.getComponentType();
+ }
+ printAnnotations(arrayType.getAnnotations(), true, arg);
+ printer.print("[]");
+ }
+ }));
+
+ if (n.getInitializer().isPresent()) {
+ printer.print(" = ");
+ n.getInitializer().get().accept(this, arg);
+ }
+ }
+
+ @Override
+ public void visit(final ArrayInitializerExpr n, final Void arg) {
+ printOrphanCommentsBeforeThisChildNode(n);
+ printComment(n.getComment(), arg);
+ printer.print("{");
+ if (!isNullOrEmpty(n.getValues())) {
+ printer.print(" ");
+ for (final Iterator<Expression> i = n.getValues().iterator(); i.hasNext(); ) {
+ final Expression expr = i.next();
+ expr.accept(this, arg);
+ if (i.hasNext()) {
+ printer.print(", ");
+ }
+ }
+ printer.print(" ");
+ }
+ printOrphanCommentsEnding(n);
+ printer.print("}");
+ }
+
+ @Override
+ public void visit(final VoidType n, final Void arg) {
+ printOrphanCommentsBeforeThisChildNode(n);
+ printComment(n.getComment(), arg);
+ printAnnotations(n.getAnnotations(), false, arg);
+ printer.print("void");
+ }
+
+ @Override
+ public void visit(final VarType n, final Void arg) {
+ printOrphanCommentsBeforeThisChildNode(n);
+ printComment(n.getComment(), arg);
+ printAnnotations(n.getAnnotations(), false, arg);
+ printer.print("var");
+ }
+
+ @Override
+ public void visit(Modifier n, Void arg) {
+ printer.print(n.getKeyword().asString());
+ printer.print(" ");
+ }
+
+ @Override
+ public void visit(final ArrayAccessExpr n, final Void arg) {
+ printOrphanCommentsBeforeThisChildNode(n);
+ printComment(n.getComment(), arg);
+ n.getName().accept(this, arg);
+ printer.print("[");
+ n.getIndex().accept(this, arg);
+ printer.print("]");
+ }
+
+ @Override
+ public void visit(final ArrayCreationExpr n, final Void arg) {
+ printOrphanCommentsBeforeThisChildNode(n);
+ printComment(n.getComment(), arg);
+ printer.print("new ");
+ n.getElementType().accept(this, arg);
+ for (ArrayCreationLevel level : n.getLevels()) {
+ level.accept(this, arg);
+ }
+ if (n.getInitializer().isPresent()) {
+ printer.print(" ");
+ n.getInitializer().get().accept(this, arg);
+ }
+ }
+
+ @Override
+ public void visit(final AssignExpr n, final Void arg) {
+ printOrphanCommentsBeforeThisChildNode(n);
+ printComment(n.getComment(), arg);
+ n.getTarget().accept(this, arg);
+ if (configuration.get(ConfigOption.SPACE_AROUND_OPERATORS).isPresent()) {
+ printer.print(" ");
+ }
+ printer.print(n.getOperator().asString());
+ if (configuration.get(ConfigOption.SPACE_AROUND_OPERATORS).isPresent()) {
+ printer.print(" ");
+ }
+ n.getValue().accept(this, arg);
+ }
+
+
+
+ /**
+ * work in progress for issue-545
+ */
+
+ @Override
+ public void visit(final BinaryExpr n, final Void arg) {
+ printOrphanCommentsBeforeThisChildNode(n);
+ printComment(n.getComment(), arg);
+ n.getLeft().accept(this, arg);
+ if (configuration.get(ConfigOption.SPACE_AROUND_OPERATORS).isPresent()) {
+ printer.print(" ");
+ }
+ printer.print(n.getOperator().asString());
+ if (configuration.get(ConfigOption.SPACE_AROUND_OPERATORS).isPresent()) {
+ printer.print(" ");
+ }
+ n.getRight().accept(this, arg);
+ }
+
+ @Override
+ public void visit(final CastExpr n, final Void arg) {
+ printOrphanCommentsBeforeThisChildNode(n);
+ printComment(n.getComment(), arg);
+ printer.print("(");
+ n.getType().accept(this, arg);
+ printer.print(") ");
+ n.getExpression().accept(this, arg);
+ }
+
+ @Override
+ public void visit(final ClassExpr n, final Void arg) {
+ printOrphanCommentsBeforeThisChildNode(n);
+ printComment(n.getComment(), arg);
+ n.getType().accept(this, arg);
+ printer.print(".class");
+ }
+
+ @Override
+ public void visit(final ConditionalExpr n, final Void arg) {
+ printOrphanCommentsBeforeThisChildNode(n);
+ printComment(n.getComment(), arg);
+ n.getCondition().accept(this, arg);
+ printer.print(" ? ");
+ n.getThenExpr().accept(this, arg);
+ printer.print(" : ");
+ n.getElseExpr().accept(this, arg);
+ }
+
+ @Override
+ public void visit(final EnclosedExpr n, final Void arg) {
+ printOrphanCommentsBeforeThisChildNode(n);
+ printComment(n.getComment(), arg);
+ printer.print("(");
+ n.getInner().accept(this, arg);
+ printer.print(")");
+ }
+
+ @Override
+ public void visit(final FieldAccessExpr n, final Void arg) {
+ printOrphanCommentsBeforeThisChildNode(n);
+ printComment(n.getComment(), arg);
+ n.getScope().accept(this, arg);
+ printer.print(".");
+ n.getName().accept(this, arg);
+ }
+
+ @Override
+ public void visit(final InstanceOfExpr n, final Void arg) {
+ printOrphanCommentsBeforeThisChildNode(n);
+ printComment(n.getComment(), arg);
+ n.getExpression().accept(this, arg);
+ printer.print(" instanceof ");
+ n.getType().accept(this, arg);
+ if(n.getName().isPresent()) {
+ printer.print(" ");
+ n.getName().get().accept(this, arg);
+ }
+ }
+
+ @Override
+ public void visit(final PatternExpr n, final Void arg) {
+ n.getType().accept(this, arg);
+ printer.print(" ");
+ n.getName().accept(this, arg);
+ }
+
+ @Override
+ public void visit(final CharLiteralExpr n, final Void arg) {
+ printOrphanCommentsBeforeThisChildNode(n);
+ printComment(n.getComment(), arg);
+ printer.print("'");
+ printer.print(n.getValue());
+ printer.print("'");
+ }
+
+ @Override
+ public void visit(final DoubleLiteralExpr n, final Void arg) {
+ printOrphanCommentsBeforeThisChildNode(n);
+ printComment(n.getComment(), arg);
+ printer.print(n.getValue());
+ }
+
+ @Override
+ public void visit(final IntegerLiteralExpr n, final Void arg) {
+ printOrphanCommentsBeforeThisChildNode(n);
+ printComment(n.getComment(), arg);
+ printer.print(n.getValue());
+ }
+
+ @Override
+ public void visit(final LongLiteralExpr n, final Void arg) {
+ printOrphanCommentsBeforeThisChildNode(n);
+ printComment(n.getComment(), arg);
+ printer.print(n.getValue());
+ }
+
+ @Override
+ public void visit(final StringLiteralExpr n, final Void arg) {
+ printOrphanCommentsBeforeThisChildNode(n);
+ printComment(n.getComment(), arg);
+ printer.print("\"");
+ printer.print(n.getValue());
+ printer.print("\"");
+ }
+
+ @Override
+ public void visit(final TextBlockLiteralExpr n, final Void arg) {
+ printOrphanCommentsBeforeThisChildNode(n);
+ printComment(n.getComment(), arg);
+ printer.print("\"\"\"");
+ printer.indent();
+ n.stripIndentOfLines().forEach(line -> {
+ printer.println();
+ printer.print(line);
+ });
+ printer.print("\"\"\"");
+ printer.unindent();
+ }
+
+ @Override
+ public void visit(final BooleanLiteralExpr n, final Void arg) {
+ printOrphanCommentsBeforeThisChildNode(n);
+ printComment(n.getComment(), arg);
+ printer.print(String.valueOf(n.getValue()));
+ }
+
+ @Override
+ public void visit(final NullLiteralExpr n, final Void arg) {
+ printOrphanCommentsBeforeThisChildNode(n);
+ printComment(n.getComment(), arg);
+ printer.print("null");
+ }
+
+ @Override
+ public void visit(final ThisExpr n, final Void arg) {
+ printOrphanCommentsBeforeThisChildNode(n);
+ printComment(n.getComment(), arg);
+ if (n.getTypeName().isPresent()) {
+ n.getTypeName().get().accept(this, arg);
+ printer.print(".");
+ }
+ printer.print("this");
+ }
+
+ @Override
+ public void visit(final SuperExpr n, final Void arg) {
+ printOrphanCommentsBeforeThisChildNode(n);
+ printComment(n.getComment(), arg);
+ if (n.getTypeName().isPresent()) {
+ n.getTypeName().get().accept(this, arg);
+ printer.print(".");
+ }
+ printer.print("super");
+ }
+
+ @Override
+ public void visit(final MethodCallExpr n, final Void arg) {
+ printOrphanCommentsBeforeThisChildNode(n);
+ printComment(n.getComment(), arg);
+
+ // determine whether we do reindenting for aligmnent at all
+ // - is it enabled?
+ // - are we in a statement where we want the alignment?
+ // - are we not directly in the argument list of a method call expression?
+ AtomicBoolean columnAlignFirstMethodChain = new AtomicBoolean();
+ if (configuration.get(ConfigOption.COLUMN_ALIGN_FIRST_METHOD_CHAIN).isPresent()) {
+ // pick the kind of expressions where vertically aligning method calls is okay.
+ if (n.findAncestor(Statement.class).map(p -> p.isReturnStmt()
+ || p.isThrowStmt()
+ || p.isAssertStmt()
+ || p.isExpressionStmt()).orElse(false)) {
+ // search for first parent that does not have its child as scope
+ Node c = n;
+ Optional<Node> p = c.getParentNode();
+ while (p.isPresent() && p.filter(NodeWithTraversableScope.class::isInstance)
+ .map(NodeWithTraversableScope.class::cast)
+ .flatMap(NodeWithTraversableScope::traverseScope)
+ .map(c::equals)
+ .orElse(false)) {
+ c = p.get();
+ p = c.getParentNode();
+ }
+
+ // check if the parent is a method call and thus we are in an argument list
+ columnAlignFirstMethodChain.set(!p.filter(MethodCallExpr.class::isInstance).isPresent());
+ }
+ }
+
+ // we are at the last method call of a call chain
+ // this means we do not start reindenting for alignment or we undo it
+ AtomicBoolean lastMethodInCallChain = new AtomicBoolean(true);
+ if (columnAlignFirstMethodChain.get()) {
+ Node node = n;
+ while (node.getParentNode()
+ .filter(NodeWithTraversableScope.class::isInstance)
+ .map(NodeWithTraversableScope.class::cast)
+ .flatMap(NodeWithTraversableScope::traverseScope)
+ .map(node::equals)
+ .orElse(false)) {
+ node = node.getParentNode().orElseThrow(AssertionError::new);
+ if (node instanceof MethodCallExpr) {
+ lastMethodInCallChain.set(false);
+ break;
+ }
+ }
+ }
+
+ // search whether there is a method call with scope in the scope already
+ // this means that we probably started reindenting for alignment there
+ AtomicBoolean methodCallWithScopeInScope = new AtomicBoolean();
+ if (columnAlignFirstMethodChain.get()) {
+ Optional<Expression> s = n.getScope();
+ while (s.filter(NodeWithTraversableScope.class::isInstance).isPresent()) {
+ Optional<Expression> parentScope = s.map(NodeWithTraversableScope.class::cast)
+ .flatMap(NodeWithTraversableScope::traverseScope);
+ if (s.filter(MethodCallExpr.class::isInstance).isPresent() && parentScope.isPresent()) {
+ methodCallWithScopeInScope.set(true);
+ break;
+ }
+ s = parentScope;
+ }
+ }
+
+ // we have a scope
+ // this means we are not the first method in the chain
+ n.getScope().ifPresent(scope -> {
+ scope.accept(this, arg);
+ if (columnAlignFirstMethodChain.get()) {
+ if (methodCallWithScopeInScope.get()) {
+ /* We're a method call on the result of something (method call, property access, ...) that is not stand alone,
+ and not the first one with scope, like:
+ we're x() in a.b().x(), or in a=b().c[15].d.e().x().
+ That means that the "else" has been executed by one of the methods in the scope chain, so that the alignment
+ is set to the "." of that method.
+ That means we will align to that "." when we start a new line: */
+ printer.println();
+ } else if (!lastMethodInCallChain.get()) {
+ /* We're the first method call on the result of something in the chain (method call, property access, ...),
+ but we are not at the same time the last method call in that chain, like:
+ we're x() in a().x().y(), or in Long.x().y.z(). That means we get to dictate the indent of following method
+ calls in this chain by setting the cursor to where we are now: just before the "."
+ that start this method call. */
+ printer.reindentWithAlignToCursor();
+ }
+ }
+ printer.print(".");
+ });
+
+ printTypeArgs(n, arg);
+ n.getName().accept(this, arg);
+ printer.duplicateIndent();
+ printArguments(n.getArguments(), arg);
+ printer.unindent();
+ if (columnAlignFirstMethodChain.get() && methodCallWithScopeInScope.get() && lastMethodInCallChain.get()) {
+ // undo the aligning after the arguments of the last method call are printed
+ printer.reindentToPreviousLevel();
+ }
+ }
+
+ @Override
+ public void visit(final ObjectCreationExpr n, final Void arg) {
+ printOrphanCommentsBeforeThisChildNode(n);
+ printComment(n.getComment(), arg);
+ if (n.getScope().isPresent()) {
+ n.getScope().get().accept(this, arg);
+ printer.print(".");
+ }
+
+ printer.print("new ");
+
+ printTypeArgs(n, arg);
+ if (!isNullOrEmpty(n.getTypeArguments().orElse(null))) {
+ printer.print(" ");
+ }
+
+ n.getType().accept(this, arg);
+
+ printArguments(n.getArguments(), arg);
+
+ if (n.getAnonymousClassBody().isPresent()) {
+ printer.println(" {");
+ printer.indent();
+ printMembers(n.getAnonymousClassBody().get(), arg);
+ printer.unindent();
+ printer.print("}");
+ }
+ }
+
+ @Override
+ public void visit(final UnaryExpr n, final Void arg) {
+ printOrphanCommentsBeforeThisChildNode(n);
+ printComment(n.getComment(), arg);
+ if (n.getOperator().isPrefix()) {
+ printer.print(n.getOperator().asString());
+ }
+
+ n.getExpression().accept(this, arg);
+
+ if (n.getOperator().isPostfix()) {
+ printer.print(n.getOperator().asString());
+ }
+ }
+
+ @Override
+ public void visit(final ConstructorDeclaration n, final Void arg) {
+ printOrphanCommentsBeforeThisChildNode(n);
+ printComment(n.getComment(), arg);
+ printMemberAnnotations(n.getAnnotations(), arg);
+ printModifiers(n.getModifiers());
+
+ printTypeParameters(n.getTypeParameters(), arg);
+ if (n.isGeneric()) {
+ printer.print(" ");
+ }
+ n.getName().accept(this, arg);
+
+ printer.print("(");
+ if (!n.getParameters().isEmpty()) {
+ for (final Iterator<Parameter> i = n.getParameters().iterator(); i.hasNext(); ) {
+ final Parameter p = i.next();
+ p.accept(this, arg);
+ if (i.hasNext()) {
+ printer.print(", ");
+ }
+ }
+ }
+ printer.print(")");
+
+ if (!isNullOrEmpty(n.getThrownExceptions())) {
+ printer.print(" throws ");
+ for (final Iterator<ReferenceType> i = n.getThrownExceptions().iterator(); i.hasNext(); ) {
+ final ReferenceType name = i.next();
+ name.accept(this, arg);
+ if (i.hasNext()) {
+ printer.print(", ");
+ }
+ }
+ }
+ printer.print(" ");
+ n.getBody().accept(this, arg);
+ }
+
+ @Override
+ public void visit(final MethodDeclaration n, final Void arg) {
+ printOrphanCommentsBeforeThisChildNode(n);
+
+ printComment(n.getComment(), arg);
+ printMemberAnnotations(n.getAnnotations(), arg);
+ printModifiers(n.getModifiers());
+ printTypeParameters(n.getTypeParameters(), arg);
+ if (!isNullOrEmpty(n.getTypeParameters())) {
+ printer.print(" ");
+ }
+
+ n.getType().accept(this, arg);
+ printer.print(" ");
+ n.getName().accept(this, arg);
+
+ printer.print("(");
+ n.getReceiverParameter().ifPresent(rp -> {
+ rp.accept(this, arg);
+ if (!isNullOrEmpty(n.getParameters())) {
+ printer.print(", ");
+ }
+ });
+ if (!isNullOrEmpty(n.getParameters())) {
+ for (final Iterator<Parameter> i = n.getParameters().iterator(); i.hasNext(); ) {
+ final Parameter p = i.next();
+ p.accept(this, arg);
+ if (i.hasNext()) {
+ printer.print(", ");
+ }
+ }
+ }
+ printer.print(")");
+
+ if (!isNullOrEmpty(n.getThrownExceptions())) {
+ printer.print(" throws ");
+ for (final Iterator<ReferenceType> i = n.getThrownExceptions().iterator(); i.hasNext(); ) {
+ final ReferenceType name = i.next();
+ name.accept(this, arg);
+ if (i.hasNext()) {
+ printer.print(", ");
+ }
+ }
+ }
+ if (!n.getBody().isPresent()) {
+ printer.print(";");
+ } else {
+ printer.print(" ");
+ n.getBody().get().accept(this, arg);
+ }
+ }
+
+ @Override
+ public void visit(final Parameter n, final Void arg) {
+ printOrphanCommentsBeforeThisChildNode(n);
+ printComment(n.getComment(), arg);
+ printAnnotations(n.getAnnotations(), false, arg);
+ printModifiers(n.getModifiers());
+ n.getType().accept(this, arg);
+ if (n.isVarArgs()) {
+ printAnnotations(n.getVarArgsAnnotations(), false, arg);
+ printer.print("...");
+ }
+ if (!(n.getType() instanceof UnknownType)) {
+ printer.print(" ");
+ }
+ n.getName().accept(this, arg);
+ }
+
+ @Override
+ public void visit(final ReceiverParameter n, final Void arg) {
+ printOrphanCommentsBeforeThisChildNode(n);
+ printComment(n.getComment(), arg);
+ printAnnotations(n.getAnnotations(), false, arg);
+ n.getType().accept(this, arg);
+ printer.print(" ");
+ n.getName().accept(this, arg);
+ }
+
+ @Override
+ public void visit(final ExplicitConstructorInvocationStmt n, final Void arg) {
+ printOrphanCommentsBeforeThisChildNode(n);
+ printComment(n.getComment(), arg);
+ if (n.isThis()) {
+ printTypeArgs(n, arg);
+ printer.print("this");
+ } else {
+ if (n.getExpression().isPresent()) {
+ n.getExpression().get().accept(this, arg);
+ printer.print(".");
+ }
+ printTypeArgs(n, arg);
+ printer.print("super");
+ }
+ printArguments(n.getArguments(), arg);
+ printer.print(";");
+ }
+
+ @Override
+ public void visit(final VariableDeclarationExpr n, final Void arg) {
+ printOrphanCommentsBeforeThisChildNode(n);
+ printComment(n.getComment(), arg);
+ if (n.getParentNode().map(ExpressionStmt.class::isInstance).orElse(false)) {
+ printMemberAnnotations(n.getAnnotations(), arg);
+ } else {
+ printAnnotations(n.getAnnotations(), false, arg);
+ }
+ printModifiers(n.getModifiers());
+
+ if (!n.getVariables().isEmpty()) {
+ n.getMaximumCommonType().ifPresent(t -> t.accept(this, arg));
+ }
+ printer.print(" ");
+
+ for (final Iterator<VariableDeclarator> i = n.getVariables().iterator(); i.hasNext(); ) {
+ final VariableDeclarator v = i.next();
+ v.accept(this, arg);
+ if (i.hasNext()) {
+ printer.print(", ");
+ }
+ }
+ }
+
+ @Override
+ public void visit(final LocalClassDeclarationStmt n, final Void arg) {
+ printOrphanCommentsBeforeThisChildNode(n);
+ printComment(n.getComment(), arg);
+ n.getClassDeclaration().accept(this, arg);
+ }
+
+ @Override
+ public void visit(final AssertStmt n, final Void arg) {
+ printOrphanCommentsBeforeThisChildNode(n);
+ printComment(n.getComment(), arg);
+ printer.print("assert ");
+ n.getCheck().accept(this, arg);
+ if (n.getMessage().isPresent()) {
+ printer.print(" : ");
+ n.getMessage().get().accept(this, arg);
+ }
+ printer.print(";");
+ }
+
+ @Override
+ public void visit(final BlockStmt n, final Void arg) {
+ printOrphanCommentsBeforeThisChildNode(n);
+ printComment(n.getComment(), arg);
+ printer.println("{");
+ if (n.getStatements() != null) {
+ printer.indent();
+ for (final Statement s : n.getStatements()) {
+ s.accept(this, arg);
+ printer.println();
+ }
+ }
+ printOrphanCommentsEnding(n);
+ printer.unindent();
+ printer.print("}");
+ }
+
+ @Override
+ public void visit(final LabeledStmt n, final Void arg) {
+ printOrphanCommentsBeforeThisChildNode(n);
+ printComment(n.getComment(), arg);
+ n.getLabel().accept(this, arg);
+ printer.print(": ");
+ n.getStatement().accept(this, arg);
+ }
+
+ @Override
+ public void visit(final EmptyStmt n, final Void arg) {
+ printOrphanCommentsBeforeThisChildNode(n);
+ printComment(n.getComment(), arg);
+ printer.print(";");
+ }
+
+ @Override
+ public void visit(final ExpressionStmt n, final Void arg) {
+ printOrphanCommentsBeforeThisChildNode(n);
+ printComment(n.getComment(), arg);
+ n.getExpression().accept(this, arg);
+ printer.print(";");
+ }
+
+ @Override
+ public void visit(final SwitchStmt n, final Void arg) {
+ printOrphanCommentsBeforeThisChildNode(n);
+ printSwitchNode(n, arg);
+ }
+
+ @Override
+ public void visit(SwitchExpr n, Void arg) {
+ printOrphanCommentsBeforeThisChildNode(n);
+ printSwitchNode(n, arg);
+ }
+
+ private void printSwitchNode(SwitchNode n, Void arg) {
+ printComment(n.getComment(), arg);
+ printer.print("switch(");
+ n.getSelector().accept(this, arg);
+ printer.println(") {");
+ if (n.getEntries() != null) {
+ indentIf(configuration.get(ConfigOption.INDENT_CASE_IN_SWITCH).isPresent());
+ for (final SwitchEntry e : n.getEntries()) {
+ e.accept(this, arg);
+ }
+ unindentIf(configuration.get(ConfigOption.INDENT_CASE_IN_SWITCH).isPresent());
+ }
+ printer.print("}");
+ }
+
+ @Override
+ public void visit(final SwitchEntry n, final Void arg) {
+ printOrphanCommentsBeforeThisChildNode(n);
+ printComment(n.getComment(), arg);
+
+ if (isNullOrEmpty(n.getLabels())) {
+ printer.print("default:");
+ } else {
+ printer.print("case ");
+ for (final Iterator<Expression> i = n.getLabels().iterator(); i.hasNext(); ) {
+ final Expression label = i.next();
+ label.accept(this, arg);
+ if (i.hasNext()) {
+ printer.print(", ");
+ }
+ }
+ printer.print(":");
+ }
+ printer.println();
+ printer.indent();
+ if (n.getStatements() != null) {
+ for (final Statement s : n.getStatements()) {
+ s.accept(this, arg);
+ printer.println();
+ }
+ }
+ printer.unindent();
+ }
+
+ @Override
+ public void visit(final BreakStmt n, final Void arg) {
+ printOrphanCommentsBeforeThisChildNode(n);
+ printComment(n.getComment(), arg);
+ printer.print("break");
+ n.getLabel().ifPresent(l -> printer.print(" ").print(l.getIdentifier()));
+ printer.print(";");
+ }
+
+ @Override
+ public void visit(final YieldStmt n, final Void arg) {
+ printOrphanCommentsBeforeThisChildNode(n);
+ printComment(n.getComment(), arg);
+ printer.print("yield ");
+ n.getExpression().accept(this, arg);
+ printer.print(";");
+ }
+
+ @Override
+ public void visit(final ReturnStmt n, final Void arg) {
+ printOrphanCommentsBeforeThisChildNode(n);
+ printComment(n.getComment(), arg);
+ printer.print("return");
+ if (n.getExpression().isPresent()) {
+ printer.print(" ");
+ n.getExpression().get().accept(this, arg);
+ }
+ printer.print(";");
+ }
+
+ @Override
+ public void visit(final EnumDeclaration n, final Void arg) {
+ printOrphanCommentsBeforeThisChildNode(n);
+ printComment(n.getComment(), arg);
+ printMemberAnnotations(n.getAnnotations(), arg);
+ printModifiers(n.getModifiers());
+
+ printer.print("enum ");
+ n.getName().accept(this, arg);
+
+ if (!n.getImplementedTypes().isEmpty()) {
+ printer.print(" implements ");
+ for (final Iterator<ClassOrInterfaceType> i = n.getImplementedTypes().iterator(); i.hasNext(); ) {
+ final ClassOrInterfaceType c = i.next();
+ c.accept(this, arg);
+ if (i.hasNext()) {
+ printer.print(", ");
+ }
+ }
+ }
+
+ printer.println(" {");
+ printer.indent();
+ if (n.getEntries().isNonEmpty()) {
+ final boolean alignVertically =
+ // Either we hit the constant amount limit in the configurations, or...
+ n.getEntries().size() > configuration.get(ConfigOption.DEFAULT_MAX_ENUM_CONSTANTS_TO_ALIGN_HORIZONTALLY).get().asInteger() ||
+ // any of the constants has a comment.
+ n.getEntries().stream().anyMatch(e -> e.getComment().isPresent());
+ printer.println();
+ for (final Iterator<EnumConstantDeclaration> i = n.getEntries().iterator(); i.hasNext(); ) {
+ final EnumConstantDeclaration e = i.next();
+ e.accept(this, arg);
+ if (i.hasNext()) {
+ if (alignVertically) {
+ printer.println(",");
+ } else {
+ printer.print(", ");
+ }
+ }
+ }
+ }
+ if (!n.getMembers().isEmpty()) {
+ printer.println(";");
+ printMembers(n.getMembers(), arg);
+ } else {
+ if (!n.getEntries().isEmpty()) {
+ printer.println();
+ }
+ }
+ printer.unindent();
+ printer.print("}");
+ }
+
+ @Override
+ public void visit(final EnumConstantDeclaration n, final Void arg) {
+ printOrphanCommentsBeforeThisChildNode(n);
+ printComment(n.getComment(), arg);
+ printMemberAnnotations(n.getAnnotations(), arg);
+ n.getName().accept(this, arg);
+
+ if (!n.getArguments().isEmpty()) {
+ printArguments(n.getArguments(), arg);
+ }
+
+ if (!n.getClassBody().isEmpty()) {
+ printer.println(" {");
+ printer.indent();
+ printMembers(n.getClassBody(), arg);
+ printer.unindent();
+ printer.println("}");
+ }
+ }
+
+ @Override
+ public void visit(final InitializerDeclaration n, final Void arg) {
+ printOrphanCommentsBeforeThisChildNode(n);
+ printComment(n.getComment(), arg);
+ if (n.isStatic()) {
+ printer.print("static ");
+ }
+ n.getBody().accept(this, arg);
+ }
+
+ @Override
+ public void visit(final IfStmt n, final Void arg) {
+ printOrphanCommentsBeforeThisChildNode(n);
+ printComment(n.getComment(), arg);
+ printer.print("if (");
+ n.getCondition().accept(this, arg);
+ final boolean thenBlock = n.getThenStmt() instanceof BlockStmt;
+ if (thenBlock) // block statement should start on the same line
+ printer.print(") ");
+ else {
+ printer.println(")");
+ printer.indent();
+ }
+ n.getThenStmt().accept(this, arg);
+ if (!thenBlock)
+ printer.unindent();
+ if (n.getElseStmt().isPresent()) {
+ if (thenBlock)
+ printer.print(" ");
+ else
+ printer.println();
+ final boolean elseIf = n.getElseStmt().orElse(null) instanceof IfStmt;
+ final boolean elseBlock = n.getElseStmt().orElse(null) instanceof BlockStmt;
+ if (elseIf || elseBlock) // put chained if and start of block statement on a same level
+ printer.print("else ");
+ else {
+ printer.println("else");
+ printer.indent();
+ }
+ if (n.getElseStmt().isPresent())
+ n.getElseStmt().get().accept(this, arg);
+ if (!(elseIf || elseBlock))
+ printer.unindent();
+ }
+ }
+
+ @Override
+ public void visit(final WhileStmt n, final Void arg) {
+ printOrphanCommentsBeforeThisChildNode(n);
+ printComment(n.getComment(), arg);
+ printer.print("while (");
+ n.getCondition().accept(this, arg);
+ printer.print(") ");
+ n.getBody().accept(this, arg);
+ }
+
+ @Override
+ public void visit(final ContinueStmt n, final Void arg) {
+ printOrphanCommentsBeforeThisChildNode(n);
+ printComment(n.getComment(), arg);
+ printer.print("continue");
+ n.getLabel().ifPresent(l -> printer.print(" ").print(l.getIdentifier()));
+ printer.print(";");
+ }
+
+ @Override
+ public void visit(final DoStmt n, final Void arg) {
+ printOrphanCommentsBeforeThisChildNode(n);
+ printComment(n.getComment(), arg);
+ printer.print("do ");
+ n.getBody().accept(this, arg);
+ printer.print(" while (");
+ n.getCondition().accept(this, arg);
+ printer.print(");");
+ }
+
+ @Override
+ public void visit(final ForEachStmt n, final Void arg) {
+ printOrphanCommentsBeforeThisChildNode(n);
+ printComment(n.getComment(), arg);
+ printer.print("for (");
+ n.getVariable().accept(this, arg);
+ printer.print(" : ");
+ n.getIterable().accept(this, arg);
+ printer.print(") ");
+ n.getBody().accept(this, arg);
+ }
+
+ @Override
+ public void visit(final ForStmt n, final Void arg) {
+ printOrphanCommentsBeforeThisChildNode(n);
+ printComment(n.getComment(), arg);
+ printer.print("for (");
+ if (n.getInitialization() != null) {
+ for (final Iterator<Expression> i = n.getInitialization().iterator(); i.hasNext(); ) {
+ final Expression e = i.next();
+ e.accept(this, arg);
+ if (i.hasNext()) {
+ printer.print(", ");
+ }
+ }
+ }
+ printer.print("; ");
+ if (n.getCompare().isPresent()) {
+ n.getCompare().get().accept(this, arg);
+ }
+ printer.print("; ");
+ if (n.getUpdate() != null) {
+ for (final Iterator<Expression> i = n.getUpdate().iterator(); i.hasNext(); ) {
+ final Expression e = i.next();
+ e.accept(this, arg);
+ if (i.hasNext()) {
+ printer.print(", ");
+ }
+ }
+ }
+ printer.print(") ");
+ n.getBody().accept(this, arg);
+ }
+
+ @Override
+ public void visit(final ThrowStmt n, final Void arg) {
+ printOrphanCommentsBeforeThisChildNode(n);
+ printComment(n.getComment(), arg);
+ printer.print("throw ");
+ n.getExpression().accept(this, arg);
+ printer.print(";");
+ }
+
+ @Override
+ public void visit(final SynchronizedStmt n, final Void arg) {
+ printOrphanCommentsBeforeThisChildNode(n);
+ printComment(n.getComment(), arg);
+ printer.print("synchronized (");
+ n.getExpression().accept(this, arg);
+ printer.print(") ");
+ n.getBody().accept(this, arg);
+ }
+
+ @Override
+ public void visit(final TryStmt n, final Void arg) {
+ printOrphanCommentsBeforeThisChildNode(n);
+ printComment(n.getComment(), arg);
+ printer.print("try ");
+ if (!n.getResources().isEmpty()) {
+ printer.print("(");
+ Iterator<Expression> resources = n.getResources().iterator();
+ boolean first = true;
+ while (resources.hasNext()) {
+ resources.next().accept(this, arg);
+ if (resources.hasNext()) {
+ printer.print(";");
+ printer.println();
+ if (first) {
+ printer.indent();
+ }
+ }
+ first = false;
+ }
+ if (n.getResources().size() > 1) {
+ printer.unindent();
+ }
+ printer.print(") ");
+ }
+ n.getTryBlock().accept(this, arg);
+ for (final CatchClause c : n.getCatchClauses()) {
+ c.accept(this, arg);
+ }
+ if (n.getFinallyBlock().isPresent()) {
+ printer.print(" finally ");
+ n.getFinallyBlock().get().accept(this, arg);
+ }
+ }
+
+ @Override
+ public void visit(final CatchClause n, final Void arg) {
+ printOrphanCommentsBeforeThisChildNode(n);
+ printComment(n.getComment(), arg);
+ printer.print(" catch (");
+ n.getParameter().accept(this, arg);
+ printer.print(") ");
+ n.getBody().accept(this, arg);
+ }
+
+ @Override
+ public void visit(final AnnotationDeclaration n, final Void arg) {
+ printOrphanCommentsBeforeThisChildNode(n);
+ printComment(n.getComment(), arg);
+ printMemberAnnotations(n.getAnnotations(), arg);
+ printModifiers(n.getModifiers());
+
+ printer.print("@interface ");
+ n.getName().accept(this, arg);
+ printer.println(" {");
+ printer.indent();
+ if (n.getMembers() != null) {
+ printMembers(n.getMembers(), arg);
+ }
+ printer.unindent();
+ printer.print("}");
+ }
+
+ @Override
+ public void visit(final AnnotationMemberDeclaration n, final Void arg) {
+ printOrphanCommentsBeforeThisChildNode(n);
+ printComment(n.getComment(), arg);
+ printMemberAnnotations(n.getAnnotations(), arg);
+ printModifiers(n.getModifiers());
+
+ n.getType().accept(this, arg);
+ printer.print(" ");
+ n.getName().accept(this, arg);
+ printer.print("()");
+ if (n.getDefaultValue().isPresent()) {
+ printer.print(" default ");
+ n.getDefaultValue().get().accept(this, arg);
+ }
+ printer.print(";");
+ }
+
+ @Override
+ public void visit(final MarkerAnnotationExpr n, final Void arg) {
+ printOrphanCommentsBeforeThisChildNode(n);
+ printComment(n.getComment(), arg);
+ printer.print("@");
+ n.getName().accept(this, arg);
+ }
+
+ @Override
+ public void visit(final SingleMemberAnnotationExpr n, final Void arg) {
+ printOrphanCommentsBeforeThisChildNode(n);
+ printComment(n.getComment(), arg);
+ printer.print("@");
+ n.getName().accept(this, arg);
+ printer.print("(");
+ n.getMemberValue().accept(this, arg);
+ printer.print(")");
+ }
+
+ @Override
+ public void visit(final NormalAnnotationExpr n, final Void arg) {
+ printOrphanCommentsBeforeThisChildNode(n);
+ printComment(n.getComment(), arg);
+ printer.print("@");
+ n.getName().accept(this, arg);
+ printer.print("(");
+ if (n.getPairs() != null) {
+ for (final Iterator<MemberValuePair> i = n.getPairs().iterator(); i.hasNext(); ) {
+ final MemberValuePair m = i.next();
+ m.accept(this, arg);
+ if (i.hasNext()) {
+ printer.print(", ");
+ }
+ }
+ }
+ printer.print(")");
+ }
+
+ @Override
+ public void visit(final MemberValuePair n, final Void arg) {
+ printOrphanCommentsBeforeThisChildNode(n);
+ printComment(n.getComment(), arg);
+ n.getName().accept(this, arg);
+ printer.print(" = ");
+ n.getValue().accept(this, arg);
+ }
+
+ @Override
+ public void visit(final LineComment n, final Void arg) {
+ if (!configuration.get(ConfigOption.PRINT_COMMENTS).isPresent()) {
+ return;
+ }
+ printer
+ .print("// ")
+ .println(normalizeEolInTextBlock(n.getContent(), "").trim());
+ }
+
+ @Override
+ public void visit(final BlockComment n, final Void arg) {
+ if (!configuration.get(ConfigOption.PRINT_COMMENTS).isPresent()) {
+ return;
+ }
+ final String commentContent = normalizeEolInTextBlock(n.getContent(), configuration.get(ConfigOption.END_OF_LINE_CHARACTER).get().asString());
+ String[] lines = commentContent.split("\\R", -1); // as BlockComment should not be formatted, -1 to preserve any trailing empty line if present
+ printer.print("/*");
+ for (int i = 0; i < (lines.length - 1); i++) {
+ printer.print(lines[i]);
+ printer.print(configuration.get(ConfigOption.END_OF_LINE_CHARACTER).get().asValue()); // Avoids introducing indentation in blockcomments. ie: do not use println() as it would trigger indentation at the next print call.
+ }
+ printer.print(lines[lines.length - 1]); // last line is not followed by a newline, and simply terminated with `*/`
+ printer.println("*/");
+ }
+
+ @Override
+ public void visit(LambdaExpr n, Void arg) {
+ printOrphanCommentsBeforeThisChildNode(n);
+ printComment(n.getComment(), arg);
+
+ final NodeList<Parameter> parameters = n.getParameters();
+ final boolean printPar = n.isEnclosingParameters();
+
+ if (printPar) {
+ printer.print("(");
+ }
+ for (Iterator<Parameter> i = parameters.iterator(); i.hasNext(); ) {
+ Parameter p = i.next();
+ p.accept(this, arg);
+ if (i.hasNext()) {
+ printer.print(", ");
+ }
+ }
+ if (printPar) {
+ printer.print(")");
+ }
+
+ printer.print(" -> ");
+ final Statement body = n.getBody();
+ if (body instanceof ExpressionStmt) {
+ // Print the expression directly
+ ((ExpressionStmt) body).getExpression().accept(this, arg);
+ } else {
+ body.accept(this, arg);
+ }
+ }
+
+ @Override
+ public void visit(MethodReferenceExpr n, Void arg) {
+ printOrphanCommentsBeforeThisChildNode(n);
+ printComment(n.getComment(), arg);
+ Expression scope = n.getScope();
+ String identifier = n.getIdentifier();
+ if (scope != null) {
+ n.getScope().accept(this, arg);
+ }
+
+ printer.print("::");
+ printTypeArgs(n, arg);
+ if (identifier != null) {
+ printer.print(identifier);
+ }
+ }
+
+ @Override
+ public void visit(TypeExpr n, Void arg) {
+ printOrphanCommentsBeforeThisChildNode(n);
+ printComment(n.getComment(), arg);
+ if (n.getType() != null) {
+ n.getType().accept(this, arg);
+ }
+ }
+
+ @Override
+ public void visit(NodeList n, Void arg) {
+ if (configuration.get(ConfigOption.ORDER_IMPORTS).isPresent() && n.size() > 0 && n.get(0) instanceof ImportDeclaration) {
+ //noinspection unchecked
+ NodeList<ImportDeclaration> modifiableList = new NodeList<>(n);
+ modifiableList.sort(
+ comparingInt((ImportDeclaration i) -> i.isStatic() ? 0 : 1)
+ .thenComparing(NodeWithName::getNameAsString));
+ for (Object node : modifiableList) {
+ ((Node) node).accept(this, arg);
+ }
+ } else {
+ for (Object node : n) {
+ ((Node) node).accept(this, arg);
+ }
+ }
+ }
+
+ @Override
+ public void visit(final ImportDeclaration n, final Void arg) {
+ printOrphanCommentsBeforeThisChildNode(n);
+ printComment(n.getComment(), arg);
+ printer.print("import ");
+ if (n.isStatic()) {
+ printer.print("static ");
+ }
+ n.getName().accept(this, arg);
+ if (n.isAsterisk()) {
+ printer.print(".*");
+ }
+ printer.println(";");
+
+ printOrphanCommentsEnding(n);
+ }
+
+
+ @Override
+ public void visit(ModuleDeclaration n, Void arg) {
+ printMemberAnnotations(n.getAnnotations(), arg);
+ if (n.isOpen()) {
+ printer.print("open ");
+ }
+ printer.print("module ");
+ n.getName().accept(this, arg);
+ printer.println(" {").indent();
+ n.getDirectives().accept(this, arg);
+ printer.unindent().println("}");
+ }
+
+ @Override
+ public void visit(ModuleRequiresDirective n, Void arg) {
+ printer.print("requires ");
+ printModifiers(n.getModifiers());
+ n.getName().accept(this, arg);
+ printer.println(";");
+ }
+
+ @Override
+ public void visit(ModuleExportsDirective n, Void arg) {
+ printer.print("exports ");
+ n.getName().accept(this, arg);
+ printPrePostFixOptionalList(n.getModuleNames(), arg, " to ", ", ", "");
+ printer.println(";");
+ }
+
+ @Override
+ public void visit(ModuleProvidesDirective n, Void arg) {
+ printer.print("provides ");
+ n.getName().accept(this, arg);
+ printPrePostFixRequiredList(n.getWith(), arg, " with ", ", ", "");
+ printer.println(";");
+ }
+
+ @Override
+ public void visit(ModuleUsesDirective n, Void arg) {
+ printer.print("uses ");
+ n.getName().accept(this, arg);
+ printer.println(";");
+ }
+
+ @Override
+ public void visit(ModuleOpensDirective n, Void arg) {
+ printer.print("opens ");
+ n.getName().accept(this, arg);
+ printPrePostFixOptionalList(n.getModuleNames(), arg, " to ", ", ", "");
+ printer.println(";");
+ }
+
+ @Override
+ public void visit(UnparsableStmt n, Void arg) {
+ printer.print("???;");
+ }
+
+ private void printOrphanCommentsBeforeThisChildNode(final Node node) {
+ if (!configuration.get(ConfigOption.PRINT_COMMENTS).isPresent()) return;
+ if (node instanceof Comment) return;
+
+ Node parent = node.getParentNode().orElse(null);
+ if (parent == null) return;
+ List<Node> everything = new ArrayList<>(parent.getChildNodes());
+ sortByBeginPosition(everything);
+ int positionOfTheChild = -1;
+ for (int i = 0; i < everything.size(); ++i) { // indexOf is by equality, so this is used to index by identity
+ if (everything.get(i) == node) {
+ positionOfTheChild = i;
+ break;
+ }
+ }
+ if (positionOfTheChild == -1) {
+ throw new AssertionError("I am not a child of my parent.");
+ }
+ int positionOfPreviousChild = -1;
+ for (int i = positionOfTheChild - 1; i >= 0 && positionOfPreviousChild == -1; i--) {
+ if (!(everything.get(i) instanceof Comment)) positionOfPreviousChild = i;
+ }
+ for (int i = positionOfPreviousChild + 1; i < positionOfTheChild; i++) {
+ Node nodeToPrint = everything.get(i);
+ if (!(nodeToPrint instanceof Comment))
+ throw new RuntimeException(
+ "Expected comment, instead " + nodeToPrint.getClass() + ". Position of previous child: "
+ + positionOfPreviousChild + ", position of child " + positionOfTheChild);
+ nodeToPrint.accept(this, null);
+ }
+ }
+
+ private void printOrphanCommentsEnding(final Node node) {
+ if (!configuration.get(ConfigOption.PRINT_COMMENTS).isPresent()) return;
+
+ // extract all nodes for which the position/range is indicated to avoid to skip orphan comments
+ List<Node> everything = node.getChildNodes().stream().filter(n->n.getRange().isPresent()).collect(Collectors.toList());
+ sortByBeginPosition(everything);
+ if (everything.isEmpty()) {
+ return;
+ }
+
+ int commentsAtEnd = 0;
+ boolean findingComments = true;
+ while (findingComments && commentsAtEnd < everything.size()) {
+ Node last = everything.get(everything.size() - 1 - commentsAtEnd);
+ findingComments = (last instanceof Comment);
+ if (findingComments) {
+ commentsAtEnd++;
+ }
+ }
+ for (int i = 0; i < commentsAtEnd; i++) {
+ everything.get(everything.size() - commentsAtEnd + i).accept(this, null);
+ }
+ }
+ private void indentIf(boolean expr){
+ if(expr)
+ printer.indent();
+ }
+ private void unindentIf(boolean expr){
+ if(expr)
+ printer.unindent();
+ }
+}
diff --git a/javaparser-core/src/main/java/com/github/javaparser/printer/SourcePrinter.java b/javaparser-core/src/main/java/com/github/javaparser/printer/SourcePrinter.java
index 3bb483a..a66afa2 100644
--- a/javaparser-core/src/main/java/com/github/javaparser/printer/SourcePrinter.java
+++ b/javaparser-core/src/main/java/com/github/javaparser/printer/SourcePrinter.java
@@ -27,12 +27,16 @@
import com.github.javaparser.Position;
import com.github.javaparser.printer.configuration.Indentation;
import com.github.javaparser.printer.configuration.Indentation.IndentType;
+import com.github.javaparser.printer.configuration.PrettyPrinterConfiguration;
import com.github.javaparser.utils.Utils;
/**
* A support class for code that outputs formatted source code.
+ * This class is no longer acceptable to use because it is not sufficiently configurable and it is too tied to a specific implementation
+ * <p> Use {@link PrintableSource interface or DefaultPrintableSource default implementation } instead.
*/
-public class SourcePrinter {
+@Deprecated
+public class SourcePrinter{
private final String endOfLineCharacter;
private final Indentation indentation;
diff --git a/javaparser-core/src/main/java/com/github/javaparser/printer/configuration/ConfigurablePrinter.java b/javaparser-core/src/main/java/com/github/javaparser/printer/configuration/ConfigurablePrinter.java
new file mode 100755
index 0000000..69e14d4
--- /dev/null
+++ b/javaparser-core/src/main/java/com/github/javaparser/printer/configuration/ConfigurablePrinter.java
@@ -0,0 +1,45 @@
+package com.github.javaparser.printer.configuration;
+
+import java.util.Optional;
+import java.util.Set;
+
+import com.github.javaparser.printer.configuration.PrinterConfiguration.ConfigOption;
+
+/*
+ * This interface defines the api for printer configuration
+ */
+public interface ConfigurablePrinter {
+
+ /*
+ * add or update an option
+ */
+ ConfigurablePrinter addOption(ConfigOption option);
+
+ /*
+ * Remove an option
+ */
+ ConfigurablePrinter removeOption(ConfigOption option);
+
+ /*
+ * True if an option is activated
+ */
+ boolean isActivated(ConfigOption option);
+
+ /*
+ * returns the specified option
+ */
+ Optional<ConfigOption> get(ConfigOption option);
+
+ /*
+ * returns all activated options
+ */
+ Set<ConfigOption> get();
+
+ /*
+ * returns the indentation parameters
+ */
+ Indentation getIndentation();
+
+ ConfigurablePrinter setIndentation(Indentation indentation);
+
+}
\ No newline at end of file
diff --git a/javaparser-core/src/main/java/com/github/javaparser/printer/PrettyPrinterConfiguration.java b/javaparser-core/src/main/java/com/github/javaparser/printer/configuration/PrettyPrinterConfiguration.java
similarity index 63%
rename from javaparser-core/src/main/java/com/github/javaparser/printer/PrettyPrinterConfiguration.java
rename to javaparser-core/src/main/java/com/github/javaparser/printer/configuration/PrettyPrinterConfiguration.java
index aa3f00b..0e50bbe 100644
--- a/javaparser-core/src/main/java/com/github/javaparser/printer/PrettyPrinterConfiguration.java
+++ b/javaparser-core/src/main/java/com/github/javaparser/printer/configuration/PrettyPrinterConfiguration.java
@@ -19,32 +19,30 @@
* GNU Lesser General Public License for more details.
*/
-package com.github.javaparser.printer;
+package com.github.javaparser.printer.configuration;
-import static com.github.javaparser.utils.Utils.SYSTEM_EOL;
import static com.github.javaparser.utils.Utils.assertNonNegative;
import static com.github.javaparser.utils.Utils.assertNotNull;
import static com.github.javaparser.utils.Utils.assertPositive;
-import java.util.function.Function;
+import java.util.Optional;
+import java.util.Set;
-import com.github.javaparser.ast.visitor.VoidVisitor;
-import com.github.javaparser.printer.configuration.Indentation;
+import com.github.javaparser.printer.PrettyPrinter;
import com.github.javaparser.printer.configuration.Indentation.IndentType;
+import com.github.javaparser.printer.configuration.PrinterConfiguration.ConfigOption;
/**
* Configuration options for the {@link PrettyPrinter}.
+ * This class is no longer acceptable to use because it is not sufficiently configurable and it is too tied to a specific implementation
+ * <p> Use {@link ConfigurablePrinter interface or PrinterConfiguration default implementation } instead.
*/
-public class PrettyPrinterConfiguration {
+@Deprecated
+public class PrettyPrinterConfiguration implements ConfigurablePrinter {
- public static final int DEFAULT_MAX_ENUM_CONSTANTS_TO_ALIGN_HORIZONTALLY = 5;
-
- private boolean orderImports = false;
- private boolean printComments = true;
- private boolean printJavadoc = true;
- private boolean spaceAroundOperators = true;
- private boolean columnAlignParameters = false;
- private boolean columnAlignFirstMethodChain = false;
+
+ ConfigurablePrinter wrapped;
+
/**
* Indent the case when it is true, don't if false
* switch(x) { switch(x) {
@@ -54,11 +52,15 @@
* return z; return x;
*} }
*/
- private boolean indentCaseInSwitch = true;
- private Indentation indentation = new Indentation(IndentType.SPACES, 4);
- private String endOfLineCharacter = SYSTEM_EOL;
- private Function<PrettyPrinterConfiguration, VoidVisitor<Void>> visitorFactory = PrettyPrintVisitor::new;
- private int maxEnumConstantsToAlignHorizontally = DEFAULT_MAX_ENUM_CONSTANTS_TO_ALIGN_HORIZONTALLY;
+ private Indentation indentation;
+
+ /*
+ * Default constructor
+ */
+ public PrettyPrinterConfiguration() {
+ this.wrapped = new PrinterConfiguration();
+ this.indentation = new Indentation(IndentType.SPACES, 4);
+ }
/*
* returns the indentation parameters
@@ -141,31 +143,35 @@
}
public boolean isOrderImports() {
- return orderImports;
+ return get(ConfigOption.ORDER_IMPORTS).isPresent();
}
public boolean isPrintComments() {
- return printComments;
+ return get(ConfigOption.PRINT_COMMENTS).isPresent();
}
public boolean isIgnoreComments() {
- return !printComments;
+ return !get(ConfigOption.PRINT_COMMENTS).isPresent();
}
- public boolean isSpaceAroundOperators() { return spaceAroundOperators; }
+ public boolean isSpaceAroundOperators() {
+ return get(ConfigOption.SPACE_AROUND_OPERATORS).isPresent();
+ }
public boolean isPrintJavadoc() {
- return printJavadoc;
+ return get(ConfigOption.PRINT_JAVADOC).isPresent();
}
public boolean isColumnAlignParameters() {
- return columnAlignParameters;
+ return get(ConfigOption.COLUMN_ALIGN_PARAMETERS).isPresent();
}
- public boolean isColumnAlignFirstMethodChain() { return columnAlignFirstMethodChain; }
+ public boolean isColumnAlignFirstMethodChain() {
+ return get(ConfigOption.COLUMN_ALIGN_FIRST_METHOD_CHAIN).isPresent();
+ }
public boolean isIndentCaseInSwitch() {
- return indentCaseInSwitch;
+ return get(ConfigOption.INDENT_CASE_IN_SWITCH).isPresent();
}
@@ -174,7 +180,7 @@
* printed.
*/
public PrettyPrinterConfiguration setPrintComments(boolean printComments) {
- this.printComments = printComments;
+ wrapped = printComments ? addOption(ConfigOption.PRINT_COMMENTS) : removeOption(ConfigOption.PRINT_COMMENTS);
return this;
}
@@ -182,7 +188,7 @@
* When true, Javadoc will be printed.
*/
public PrettyPrinterConfiguration setPrintJavadoc(boolean printJavadoc) {
- this.printJavadoc = printJavadoc;
+ wrapped = printJavadoc ? addOption(ConfigOption.PRINT_JAVADOC) : removeOption(ConfigOption.PRINT_JAVADOC);
return this;
}
@@ -190,47 +196,34 @@
* Set if there should be spaces between operators
*/
public PrettyPrinterConfiguration setSpaceAroundOperators(boolean spaceAroundOperators){
- this.spaceAroundOperators = spaceAroundOperators;
+ wrapped = spaceAroundOperators ? addOption(ConfigOption.SPACE_AROUND_OPERATORS) : removeOption(ConfigOption.SPACE_AROUND_OPERATORS);
return this;
}
public PrettyPrinterConfiguration setColumnAlignParameters(boolean columnAlignParameters) {
- this.columnAlignParameters = columnAlignParameters;
+ wrapped = columnAlignParameters ? addOption(ConfigOption.COLUMN_ALIGN_PARAMETERS) : removeOption(ConfigOption.COLUMN_ALIGN_PARAMETERS);
return this;
}
public PrettyPrinterConfiguration setColumnAlignFirstMethodChain(boolean columnAlignFirstMethodChain) {
- this.columnAlignFirstMethodChain = columnAlignFirstMethodChain;
+ wrapped = columnAlignFirstMethodChain ? addOption(ConfigOption.COLUMN_ALIGN_FIRST_METHOD_CHAIN) : removeOption(ConfigOption.COLUMN_ALIGN_FIRST_METHOD_CHAIN);
return this;
}
public PrettyPrinterConfiguration setIndentCaseInSwitch(boolean indentInSwitch) {
- this.indentCaseInSwitch = indentInSwitch;
- return this;
- }
-
- public Function<PrettyPrinterConfiguration, VoidVisitor<Void>> getVisitorFactory() {
- return visitorFactory;
- }
-
- /**
- * Set the factory that creates the PrettyPrintVisitor. By changing this you can make the PrettyPrinter use a custom
- * PrettyPrinterVisitor.
- */
- public PrettyPrinterConfiguration setVisitorFactory(Function<PrettyPrinterConfiguration, VoidVisitor<Void>> visitorFactory) {
- this.visitorFactory = assertNotNull(visitorFactory);
+ wrapped = indentInSwitch ? addOption(ConfigOption.INDENT_CASE_IN_SWITCH) : removeOption(ConfigOption.INDENT_CASE_IN_SWITCH);
return this;
}
public String getEndOfLineCharacter() {
- return endOfLineCharacter;
+ return get(ConfigOption.END_OF_LINE_CHARACTER).get().asValue();
}
/**
* Set the character to append when a line should end. Example values: "\n", "\r\n", "".
*/
public PrettyPrinterConfiguration setEndOfLineCharacter(String endOfLineCharacter) {
- this.endOfLineCharacter = assertNotNull(endOfLineCharacter);
+ addOption(ConfigOption.END_OF_LINE_CHARACTER.value(endOfLineCharacter));
return this;
}
@@ -238,14 +231,14 @@
* When true, orders imports by alphabetically.
*/
public PrettyPrinterConfiguration setOrderImports(boolean orderImports) {
- this.orderImports = orderImports;
+ wrapped = orderImports ? addOption(ConfigOption.ORDER_IMPORTS) : removeOption(ConfigOption.ORDER_IMPORTS);
return this;
}
public int getMaxEnumConstantsToAlignHorizontally() {
- return maxEnumConstantsToAlignHorizontally;
+ return get(ConfigOption.DEFAULT_MAX_ENUM_CONSTANTS_TO_ALIGN_HORIZONTALLY).get().asInteger();
}
/**
@@ -272,7 +265,32 @@
* Set it to 1 or less to always align vertically.
*/
public PrettyPrinterConfiguration setMaxEnumConstantsToAlignHorizontally(int maxEnumConstantsToAlignHorizontally) {
- this.maxEnumConstantsToAlignHorizontally = maxEnumConstantsToAlignHorizontally;
+ addOption(ConfigOption.DEFAULT_MAX_ENUM_CONSTANTS_TO_ALIGN_HORIZONTALLY.value(maxEnumConstantsToAlignHorizontally));
return this;
}
+
+ @Override
+ public ConfigurablePrinter addOption(ConfigOption option) {
+ return wrapped.addOption(option);
+ }
+
+ @Override
+ public boolean isActivated(ConfigOption option) {
+ return wrapped.isActivated(option);
+ }
+
+ @Override
+ public Optional<ConfigOption> get(ConfigOption option) {
+ return wrapped.get(option);
+ }
+
+ @Override
+ public Set<ConfigOption> get() {
+ return wrapped.get();
+ }
+
+ @Override
+ public ConfigurablePrinter removeOption(ConfigOption option) {
+ return wrapped.removeOption(option);
+ }
}
diff --git a/javaparser-core/src/main/java/com/github/javaparser/printer/configuration/PrinterConfiguration.java b/javaparser-core/src/main/java/com/github/javaparser/printer/configuration/PrinterConfiguration.java
new file mode 100755
index 0000000..36b558d
--- /dev/null
+++ b/javaparser-core/src/main/java/com/github/javaparser/printer/configuration/PrinterConfiguration.java
@@ -0,0 +1,216 @@
+/*
+ * Copyright (C) 2011, 2013-2020 The JavaParser Team.
+ *
+ * This file is part of JavaParser.
+ *
+ * JavaParser can be used either under the terms of
+ * a) the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ * b) the terms of the Apache License
+ *
+ * You should have received a copy of both licenses in LICENCE.LGPL and
+ * LICENCE.APACHE. Please refer to those files for details.
+ *
+ * JavaParser is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ */
+
+package com.github.javaparser.printer.configuration;
+
+import java.util.Arrays;
+import java.util.HashSet;
+import java.util.Optional;
+import java.util.Set;
+
+import com.github.javaparser.printer.Printable;
+import com.github.javaparser.printer.configuration.Indentation.IndentType;
+import com.github.javaparser.utils.Utils;
+
+/**
+ * Configuration options for the {@link Printable}.
+ */
+public class PrinterConfiguration implements ConfigurablePrinter {
+
+ public enum ConfigOption {
+ ORDER_IMPORTS(Boolean.class),
+ PRINT_COMMENTS(Boolean.class),
+ PRINT_JAVADOC(Boolean.class),
+ SPACE_AROUND_OPERATORS(Boolean.class),
+ COLUMN_ALIGN_PARAMETERS(Boolean.class),
+ COLUMN_ALIGN_FIRST_METHOD_CHAIN(Boolean.class),
+ /**
+ * Indent the case when it is true, don't if false
+ * switch(x) { switch(x) {
+ * case 1: case 1:
+ * return y; return y;
+ * case 2: case 2:
+ * return z; return x;
+ *} }
+ */
+ INDENT_CASE_IN_SWITCH(Boolean.class),
+ /**
+ * By default enum constants get aligned like this:
+ * <pre>
+ * enum X {
+ * A, B, C, D
+ * }
+ * </pre>
+ * until the amount of constants passes this value (5 by default).
+ * Then they get aligned like this:
+ * <pre>
+ * enum X {
+ * A,
+ * B,
+ * C,
+ * D,
+ * E,
+ * F,
+ * G
+ * }
+ * </pre>
+ * Set it to a large number to always align horizontally.
+ * Set it to 1 or less to always align vertically.
+ */
+ DEFAULT_MAX_ENUM_CONSTANTS_TO_ALIGN_HORIZONTALLY(Integer.valueOf(5)),
+ END_OF_LINE_CHARACTER(Utils.SYSTEM_EOL);
+
+ Object value;
+
+ Class type;
+
+ // Option without value
+ <T> ConfigOption(Class clazz) {
+ this.type = clazz;
+ }
+
+ // Option with initial value
+ ConfigOption(Object value) {
+ value(value);
+ }
+
+ /*
+ * Set a value to an option
+ */
+ public ConfigOption value(Object value) {
+ Utils.assertNotNull(value);
+ this.value = value;
+ this.type = value.getClass();
+ return this;
+ }
+
+ /*
+ * returns True if the option has a value
+ */
+ public boolean hasValue() {
+ return value != null;
+ }
+
+ /*
+ * returns the value as an Integer
+ */
+ public Integer asInteger() {
+ return cast();
+ }
+
+ /*
+ * returns the value as a String
+ */
+ public String asString() {
+ return cast();
+ }
+
+ /*
+ * returns the value as a Boolean
+ */
+ public Boolean asBoolean() {
+ return cast();
+ }
+
+ public <T extends Object> T asValue() {
+ return cast();
+ }
+
+ private <T extends Object> T cast() {
+ if (!hasValue()) throw new IllegalArgumentException(String.format("The option %s has no value", this.name()));
+ if (type.isAssignableFrom(value.getClass()))
+ return (T) type.cast(value);
+ throw new IllegalArgumentException(String.format("%s cannot be cast to %s", value, type.getName()));
+ }
+ }
+
+ // contains all available options
+ // an option contained in the set is considered as activated
+ private Set<ConfigOption> options = new HashSet<ConfigOption>(Arrays.asList(
+ ConfigOption.PRINT_COMMENTS,
+ ConfigOption.PRINT_JAVADOC,
+ ConfigOption.SPACE_AROUND_OPERATORS,
+ ConfigOption.INDENT_CASE_IN_SWITCH,
+ ConfigOption.DEFAULT_MAX_ENUM_CONSTANTS_TO_ALIGN_HORIZONTALLY.value(Integer.valueOf(5)),
+ ConfigOption.END_OF_LINE_CHARACTER.value(Utils.SYSTEM_EOL)
+ ));
+
+ private Indentation indentation = new Indentation(IndentType.SPACES, 4);
+
+ // private Function<PrinterConfiguration, VoidVisitor<Void>> visitorFactory = PrettyPrintVisitor::new;
+
+ /*
+ * add or update an option
+ */
+ @Override
+ public ConfigurablePrinter addOption(ConfigOption option) {
+ removeOption(option);
+ options.add(option);
+ return this;
+ }
+
+ /*
+ * add or update an option
+ */
+ @Override
+ public ConfigurablePrinter removeOption(ConfigOption option) {
+ options.remove(option);
+ return this;
+ }
+
+ /*
+ * True if an option is activated
+ */
+ @Override
+ public boolean isActivated(ConfigOption option) {
+ return options.contains(option);
+ }
+
+ /*
+ * returns the specified option
+ */
+ @Override
+ public Optional<ConfigOption> get(ConfigOption option) {
+ return options.stream().filter(o-> o.equals(option)).findFirst();
+ }
+
+ /*
+ * returns all activated options
+ */
+ @Override
+ public Set<ConfigOption> get() {
+ return options;
+ }
+
+ /*
+ * returns the indentation parameters
+ */
+ @Override
+ public Indentation getIndentation() {
+ return indentation;
+ }
+
+ @Override
+ public ConfigurablePrinter setIndentation(Indentation indentation) {
+ this.indentation = indentation;
+ return this;
+ }
+
+}
diff --git a/javaparser-core/src/main/java/com/github/javaparser/utils/SourceRoot.java b/javaparser-core/src/main/java/com/github/javaparser/utils/SourceRoot.java
index 3a0224b..4c3a277 100644
--- a/javaparser-core/src/main/java/com/github/javaparser/utils/SourceRoot.java
+++ b/javaparser-core/src/main/java/com/github/javaparser/utils/SourceRoot.java
@@ -21,12 +21,15 @@
package com.github.javaparser.utils;
-import com.github.javaparser.JavaParser;
-import com.github.javaparser.ParseProblemException;
-import com.github.javaparser.ParseResult;
-import com.github.javaparser.ParserConfiguration;
-import com.github.javaparser.ast.CompilationUnit;
-import com.github.javaparser.printer.PrettyPrinter;
+import static com.github.javaparser.ParseStart.COMPILATION_UNIT;
+import static com.github.javaparser.Providers.provider;
+import static com.github.javaparser.utils.CodeGenerationUtils.fileInPackageAbsolutePath;
+import static com.github.javaparser.utils.CodeGenerationUtils.fileInPackageRelativePath;
+import static com.github.javaparser.utils.CodeGenerationUtils.packageAbsolutePath;
+import static com.github.javaparser.utils.Utils.assertNotNull;
+import static java.nio.file.FileVisitResult.CONTINUE;
+import static java.nio.file.FileVisitResult.SKIP_SUBTREE;
+import static java.nio.file.FileVisitResult.TERMINATE;
import java.io.IOException;
import java.nio.charset.Charset;
@@ -45,11 +48,12 @@
import java.util.regex.Pattern;
import java.util.stream.Collectors;
-import static com.github.javaparser.ParseStart.COMPILATION_UNIT;
-import static com.github.javaparser.Providers.provider;
-import static com.github.javaparser.utils.CodeGenerationUtils.*;
-import static com.github.javaparser.utils.Utils.assertNotNull;
-import static java.nio.file.FileVisitResult.*;
+import com.github.javaparser.JavaParser;
+import com.github.javaparser.ParseProblemException;
+import com.github.javaparser.ParseResult;
+import com.github.javaparser.ParserConfiguration;
+import com.github.javaparser.ast.CompilationUnit;
+import com.github.javaparser.printer.PrettyPrintable;
/**
* A collection of Java source files located in one directory and its subdirectories on the file system. The root directory
@@ -79,7 +83,7 @@
private final Path root;
private final Map<Path, ParseResult<CompilationUnit>> cache = new ConcurrentHashMap<>();
private ParserConfiguration parserConfiguration = new ParserConfiguration();
- private Function<CompilationUnit, String> printer = new PrettyPrinter()::print;
+ private Function<CompilationUnit, String> printer = new PrettyPrintable()::print;
private static final Pattern JAVA_IDENTIFIER = Pattern.compile("\\p{javaJavaIdentifierStart}\\p{javaJavaIdentifierPart}*");
/**
diff --git a/javaparser-symbol-solver-testing/src/test/java/com/github/javaparser/symbolsolver/Issue2764Test.java b/javaparser-symbol-solver-testing/src/test/java/com/github/javaparser/symbolsolver/Issue2764Test.java
index c2c4c44..472aa21 100755
--- a/javaparser-symbol-solver-testing/src/test/java/com/github/javaparser/symbolsolver/Issue2764Test.java
+++ b/javaparser-symbol-solver-testing/src/test/java/com/github/javaparser/symbolsolver/Issue2764Test.java
@@ -10,7 +10,7 @@
import com.github.javaparser.ast.expr.UnaryExpr;
import com.github.javaparser.ast.stmt.Statement;
import com.github.javaparser.printer.PrettyPrinter;
-import com.github.javaparser.printer.PrettyPrinterConfiguration;
+import com.github.javaparser.printer.configuration.PrettyPrinterConfiguration;
import com.github.javaparser.resolution.declarations.ResolvedValueDeclaration;
import com.github.javaparser.symbolsolver.model.resolution.TypeSolver;
import com.github.javaparser.symbolsolver.resolution.typesolvers.ReflectionTypeSolver;
diff --git a/javaparser-symbol-solver-testing/src/test/java/com/github/javaparser/symbolsolver/Issue546Test.java b/javaparser-symbol-solver-testing/src/test/java/com/github/javaparser/symbolsolver/Issue546Test.java
index 39c5c94..56ce99b 100644
--- a/javaparser-symbol-solver-testing/src/test/java/com/github/javaparser/symbolsolver/Issue546Test.java
+++ b/javaparser-symbol-solver-testing/src/test/java/com/github/javaparser/symbolsolver/Issue546Test.java
@@ -2,7 +2,7 @@
import com.github.javaparser.ast.stmt.Statement;
import com.github.javaparser.printer.PrettyPrinter;
-import com.github.javaparser.printer.PrettyPrinterConfiguration;
+import com.github.javaparser.printer.configuration.PrettyPrinterConfiguration;
import com.github.javaparser.utils.LineSeparator;
import org.junit.jupiter.api.Test;