diff --git a/src/main/java/spoon/reflect/visitor/DefaultJavaPrettyPrinter.java b/src/main/java/spoon/reflect/visitor/DefaultJavaPrettyPrinter.java index 44398111573..6986322276a 100644 --- a/src/main/java/spoon/reflect/visitor/DefaultJavaPrettyPrinter.java +++ b/src/main/java/spoon/reflect/visitor/DefaultJavaPrettyPrinter.java @@ -282,7 +282,7 @@ public DefaultJavaPrettyPrinter scan(CtElement e) { context.elementStack.push(e); if (env.isPreserveLineNumbers()) { if (!(e instanceof CtNamedElement)) { - printer.adjustPosition(e, sourceCompilationUnit); + printer.adjustStartPosition(e); } } e.accept(this); @@ -436,9 +436,10 @@ public void visitCtBlock(CtBlock block) { } } printer.decTab(); + printer.adjustEndPosition(block); if (env.isPreserveLineNumbers()) { if (!block.isImplicit()) { - printer.write("}"); + printer.writeTabs().write("}"); } } else { printer.writeln().writeTabs(); @@ -528,7 +529,7 @@ public void visitCtClass(CtClass ctClass) { // lst.addAll(elementPrinterHelper.getComments(ctClass, CommentOffset.INSIDE)); printer.write(" {").incTab(); elementPrinterHelper.writeElementList(ctClass.getTypeMembers()); - printer.decTab().writeTabs().write("}"); + printer.adjustEndPosition(ctClass).decTab().writeTabs().write("}"); context.popCurrentThis(); } @@ -1092,7 +1093,7 @@ public void visitCtInvocation(CtInvocation invocation) { elementPrinterHelper.writeActualTypeArguments(invocation); if (env.isPreserveLineNumbers()) { - printer.adjustPosition(invocation, sourceCompilationUnit); + printer.adjustStartPosition(invocation); } printer.write(invocation.getExecutable().getSimpleName()); } @@ -1163,7 +1164,7 @@ public void visitCtLocalVariable(CtLocalVariable localVariable) { enterCtStatement(localVariable); } if (env.isPreserveLineNumbers()) { - printer.adjustPosition(localVariable, sourceCompilationUnit); + printer.adjustStartPosition(localVariable); } if (!context.noTypeDecl()) { elementPrinterHelper.writeModifiers(localVariable); @@ -1185,7 +1186,7 @@ public void visitCtLocalVariableReference(CtLocalVariableReference refere @Override public void visitCtCatchVariable(CtCatchVariable catchVariable) { if (env.isPreserveLineNumbers()) { - printer.adjustPosition(catchVariable, sourceCompilationUnit); + printer.adjustStartPosition(catchVariable); } elementPrinterHelper.writeModifiers(catchVariable); scan(catchVariable.getType()); @@ -1813,7 +1814,12 @@ public void calculate(CompilationUnit sourceCompilationUnit, List> typ elementPrinterHelper.writeHeader(types, imports); for (CtType t : types) { scan(t); - printer.writeln().writeln().writeTabs(); + if (!env.isPreserveLineNumbers()) { + // saving lines and chars + printer.writeln().writeln().writeTabs(); + } else { + printer.adjustEndPosition(t); + } } } diff --git a/src/main/java/spoon/reflect/visitor/printer/ElementPrinterHelper.java b/src/main/java/spoon/reflect/visitor/printer/ElementPrinterHelper.java index 0882ead28fd..0f50d2a7cd5 100644 --- a/src/main/java/spoon/reflect/visitor/printer/ElementPrinterHelper.java +++ b/src/main/java/spoon/reflect/visitor/printer/ElementPrinterHelper.java @@ -88,7 +88,7 @@ public void writeModifiers(CtModifiable modifiable) { public void visitCtNamedElement(CtNamedElement namedElement, CompilationUnit sourceCompilationUnit) { writeAnnotations(namedElement); if (env.isPreserveLineNumbers()) { - printer.adjustPosition(namedElement, sourceCompilationUnit); + printer.adjustStartPosition(namedElement); } } @@ -261,7 +261,6 @@ public void writeHeader(List> types, Collection imports) if (!types.isEmpty()) { for (CtType ctType : types) { writeComment(ctType, CommentOffset.TOP_FILE); - printer.writeln().writeln().writeTabs(); } // writing the header package if (!types.get(0).getPackage().isUnnamedPackage()) { diff --git a/src/main/java/spoon/reflect/visitor/printer/PrinterHelper.java b/src/main/java/spoon/reflect/visitor/printer/PrinterHelper.java index 9b19bc3a1f9..e4c01edfd19 100644 --- a/src/main/java/spoon/reflect/visitor/printer/PrinterHelper.java +++ b/src/main/java/spoon/reflect/visitor/printer/PrinterHelper.java @@ -16,7 +16,6 @@ */ package spoon.reflect.visitor.printer; -import org.apache.log4j.Level; import spoon.compiler.Environment; import spoon.reflect.code.BinaryOperatorKind; import spoon.reflect.code.UnaryOperatorKind; @@ -160,24 +159,30 @@ private boolean isWhite(char c) { return (c == ' ') || (c == '\t') || (c == '\n') || (c == '\r'); } - public void adjustPosition(CtElement e, CompilationUnit unitExpected) { - if (e.getPosition() != null && !e.isImplicit() && e.getPosition().getCompilationUnit() != null && e.getPosition().getCompilationUnit() == unitExpected) { + public PrinterHelper adjustStartPosition(CtElement e) { + if (e.getPosition() != null && !e.isImplicit()) { + // we should add some lines while (line < e.getPosition().getLine()) { writeln(); } // trying to remove some lines while (line > e.getPosition().getLine()) { if (!removeLine()) { - if (line > e.getPosition().getEndLine()) { - final String message = "cannot adjust position of " + e.getClass().getSimpleName() + " '" // - + e.getShortRepresentation() + "' " + " to match lines: " + line + " > [" // - + e.getPosition().getLine() + ", " + e.getPosition().getEndLine() + "]"; // - env.report(null, Level.WARN, e, message); - } break; } } } + return this; + } + + public PrinterHelper adjustEndPosition(CtElement e) { + if (env.isPreserveLineNumbers() && e.getPosition() != null) { + // let's add lines if required + while (line < e.getPosition().getEndLine()) { + writeln(); + } + } + return this; } public void undefineLine() { diff --git a/src/main/java/spoon/support/compiler/jdt/JDTBasedSpoonCompiler.java b/src/main/java/spoon/support/compiler/jdt/JDTBasedSpoonCompiler.java index ff14d04245c..d9e128bc3df 100644 --- a/src/main/java/spoon/support/compiler/jdt/JDTBasedSpoonCompiler.java +++ b/src/main/java/spoon/support/compiler/jdt/JDTBasedSpoonCompiler.java @@ -504,6 +504,7 @@ protected void generateProcessedSourceFilesUsingCUs() { IOUtils.copy(is, new FileOutputStream(file)); + if (!printedFiles.contains(file)) { printedFiles.add(file); } diff --git a/src/test/java/spoon/test/prettyprinter/DefaultPrettyPrinterTest.java b/src/test/java/spoon/test/prettyprinter/DefaultPrettyPrinterTest.java index 595ed855aa6..4debb71f4e3 100644 --- a/src/test/java/spoon/test/prettyprinter/DefaultPrettyPrinterTest.java +++ b/src/test/java/spoon/test/prettyprinter/DefaultPrettyPrinterTest.java @@ -24,6 +24,8 @@ import java.io.File; import java.io.FileInputStream; +import java.io.FileReader; +import java.util.ArrayList; import java.util.Arrays; import java.util.List; @@ -261,7 +263,7 @@ public void printClassCreatedWithSpoon() throws Exception { File javaFile = new File(pathname); assertTrue(javaFile.exists()); - assertEquals(nl + nl + "package foo;" + nl + nl + nl + "class Bar {}" + nl + nl, + assertEquals("package foo;" + nl + nl + nl + "class Bar {}" + nl + nl, IOUtils.toString(new FileInputStream(javaFile), "UTF-8")); } @@ -291,4 +293,5 @@ public void testTernaryParenthesesOnLocalVariable() { snippet = launcher.getFactory().Code().createCodeSnippetStatement(compile.toString()); assertEquals(compile, snippet.compile()); } + } diff --git a/src/test/java/spoon/test/prettyprinter/LinesTest.java b/src/test/java/spoon/test/prettyprinter/LinesTest.java index cc8932ea157..db790977c82 100644 --- a/src/test/java/spoon/test/prettyprinter/LinesTest.java +++ b/src/test/java/spoon/test/prettyprinter/LinesTest.java @@ -1,14 +1,31 @@ package spoon.test.prettyprinter; +import org.apache.commons.io.IOUtils; import org.junit.Before; import org.junit.Test; import spoon.Launcher; import spoon.compiler.SpoonResourceHelper; +import spoon.reflect.code.CtThisAccess; +import spoon.reflect.code.CtTypeAccess; +import spoon.reflect.declaration.CtElement; +import spoon.reflect.declaration.CtNamedElement; import spoon.reflect.declaration.CtType; import spoon.reflect.factory.Factory; +import spoon.reflect.reference.CtTypeReference; import spoon.reflect.visitor.DefaultJavaPrettyPrinter; +import spoon.reflect.visitor.filter.NameFilter; +import spoon.reflect.visitor.filter.TypeFilter; +import spoon.test.prettyprinter.testclasses.QualifiedThisRef; + +import java.io.File; +import java.io.FileReader; +import java.util.ArrayList; +import java.util.List; import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotSame; +import static org.junit.Assert.assertTrue; +import static spoon.test.limits.StaticFieldAccesOnInstance.test; public class LinesTest { @@ -45,4 +62,50 @@ public void testPrettyPrinterWithLines() throws Exception { } + @Test + public void testIdenticalPrettyPrinter() throws Exception{ + // contract: the end line should also be preserved + + // setup + String[] options = {"--output-type", "compilationunits", + "--output", "target/testIdenticalPrettyPrinter", + // those three options together are the closest to what the developer wrote + "--enable-comments", "--lines", "--with-imports"}; + + List paths = new ArrayList<>(); + paths.add("spoon/test/prettyprinter/testclasses/A.java"); + paths.add("spoon/test/prettyprinter/testclasses/AClass.java"); + //paths.add("spoon/test/prettyprinter/testclasses/QualifiedThisRef.java"); + //paths.add("spoon/test/prettyprinter/testclasses/ImportStatic.java"); + //paths.add("spoon/test/prettyprinter/testclasses/QualifiedThisRef.java"); + //paths.add("spoon/test/prettyprinter/testclasses/Rule.java"); + //paths.add("spoon/test/prettyprinter/testclasses/TypeIdentifierCollision.java"); + + + final Launcher launcher = new Launcher(); + launcher.setArgs(options); + for (String path : paths) { + launcher.addInputResource("./src/test/java/" + path); + } + launcher.run(); + + final Launcher launcher2 = new Launcher(); + launcher2.setArgs(options); + for (String path : paths) { + launcher2.addInputResource("./target/testIdenticalPrettyPrinter/" + path); + } + launcher2.run(); + + int n=0; + List elements = launcher.getModel().getElements(new TypeFilter<>(CtElement.class)); + for (int i = 0; i < elements.size(); i++) { + n++; + CtElement e = elements.get(i); + CtElement el2 = launcher2.getModel().getElements(new TypeFilter<>(CtElement.class)).get(i); + assertNotSame(e, el2); + assertEquals(e.toString() + " not handled", e.getPosition().getLine(), el2.getPosition().getLine()); + assertEquals(e.toString() + " not handled", e.getPosition().getEndLine(), el2.getPosition().getEndLine()); + } + assertTrue(n>20); + } }