1 package com.github.javaparser.printer.lexicalpreservation; 2 3 import com.github.javaparser.*; 4 import com.github.javaparser.ast.*; 5 import com.github.javaparser.ast.body.*; 6 import com.github.javaparser.ast.expr.*; 7 import com.github.javaparser.ast.stmt.*; 8 import com.github.javaparser.ast.type.Type; 9 import com.github.javaparser.ast.type.UnionType; 10 import com.github.javaparser.ast.type.VoidType; 11 import com.github.javaparser.ast.visitor.ModifierVisitor; 12 import com.github.javaparser.ast.visitor.Visitable; 13 import org.junit.Test; 14 15 import java.io.IOException; 16 import java.util.Arrays; 17 import java.util.List; 18 import java.util.stream.Collectors; 19 20 import static com.github.javaparser.printer.lexicalpreservation.LexicalPreservingPrinter.NODE_TEXT_DATA; 21 import static com.github.javaparser.utils.TestUtils.assertEqualsNoEol; 22 import static com.github.javaparser.utils.Utils.EOL; 23 import static org.junit.Assert.assertEquals; 24 import static org.junit.Assert.assertTrue; 25 26 public class LexicalPreservingPrinterTest extends AbstractLexicalPreservingTest { 27 private NodeText getTextForNode(Node node) { 28 return node.getData(NODE_TEXT_DATA); 29 } 30 31 32 // 33 // Tests on TextNode definition 34 // 35 36 @Test 37 public void checkNodeTextCreatedForSimplestClass() { 38 considerCode("class A {}"); 39 40 // CU 41 assertEquals(1, getTextForNode(cu).numberOfElements()); 42 assertEquals(true, getTextForNode(cu).getTextElement(0) instanceof ChildTextElement); 43 assertEquals(cu.getClassByName("A").get(), ((ChildTextElement)getTextForNode(cu).getTextElement(0)).getChild()); 44 45 // Class 46 ClassOrInterfaceDeclaration classA = cu.getClassByName("A").get(); 47 assertEquals(7, getTextForNode(classA).numberOfElements()); 48 assertEquals("class", getTextForNode(classA).getTextElement(0).expand()); 49 assertEquals(" ", getTextForNode(classA).getTextElement(1).expand()); 50 assertEquals("A", getTextForNode(classA).getTextElement(2).expand()); 51 assertEquals(" ", getTextForNode(classA).getTextElement(3).expand()); 52 assertEquals("{", getTextForNode(classA).getTextElement(4).expand()); 53 assertEquals("}", getTextForNode(classA).getTextElement(5).expand()); 54 assertEquals("", getTextForNode(classA).getTextElement(6).expand()); 55 assertEquals(true, getTextForNode(classA).getTextElement(6) instanceof TokenTextElement); 56 assertEquals(GeneratedJavaParserConstants.EOF, ((TokenTextElement)getTextForNode(classA).getTextElement(6)).getTokenKind()); 57 } 58 59 @Test 60 public void checkNodeTextCreatedForField() { 61 String code = "class A {int i;}"; 62 considerCode(code); 63 64 ClassOrInterfaceDeclaration classA = cu.getClassByName("A").get(); 65 FieldDeclaration fd = classA.getFieldByName("i").get(); 66 NodeText nodeText = LexicalPreservingPrinter.getOrCreateNodeText(fd); 67 assertEquals(Arrays.asList("int", " ", "i", ";"), 68 nodeText.getElements().stream().map(TextElement::expand).collect(Collectors.toList())); 69 } 70 71 @Test 72 public void checkNodeTextCreatedForVariableDeclarator() { 73 String code = "class A {int i;}"; 74 considerCode(code); 75 76 ClassOrInterfaceDeclaration classA = cu.getClassByName("A").get(); 77 FieldDeclaration fd = classA.getFieldByName("i").get(); 78 VariableDeclarator vd = fd.getVariables().get(0); 79 NodeText nodeText = LexicalPreservingPrinter.getOrCreateNodeText(vd); 80 assertEquals(Arrays.asList("i"), 81 nodeText.getElements().stream().map(TextElement::expand).collect(Collectors.toList())); 82 } 83 84 @Test 85 public void checkNodeTextCreatedForMethod() { 86 String code = "class A {void foo(int p1, float p2) { }}"; 87 considerCode(code); 88 89 ClassOrInterfaceDeclaration classA = cu.getClassByName("A").get(); 90 MethodDeclaration md = classA.getMethodsByName("foo").get(0); 91 NodeText nodeText = LexicalPreservingPrinter.getOrCreateNodeText(md); 92 assertEquals(Arrays.asList("void", " ", "foo", "(", "int p1", ",", " ", "float p2", ")", " ", "{ }"), 93 nodeText.getElements().stream().map(TextElement::expand).collect(Collectors.toList())); 94 } 95 96 @Test 97 public void checkNodeTextCreatedForMethodParameter() { 98 String code = "class A {void foo(int p1, float p2) { }}"; 99 considerCode(code); 100 101 ClassOrInterfaceDeclaration classA = cu.getClassByName("A").get(); 102 MethodDeclaration md = classA.getMethodsByName("foo").get(0); 103 Parameter p1 = md.getParameterByName("p1").get(); 104 NodeText nodeText = LexicalPreservingPrinter.getOrCreateNodeText(p1); 105 assertEquals(Arrays.asList("int", " ", "p1"), 106 nodeText.getElements().stream().map(TextElement::expand).collect(Collectors.toList())); 107 } 108 109 @Test 110 public void checkNodeTextCreatedForPrimitiveType() { 111 String code = "class A {void foo(int p1, float p2) { }}"; 112 considerCode(code); 113 114 ClassOrInterfaceDeclaration classA = cu.getClassByName("A").get(); 115 MethodDeclaration md = classA.getMethodsByName("foo").get(0); 116 Parameter p1 = md.getParameterByName("p1").get(); 117 Type t = p1.getType(); 118 NodeText nodeText = LexicalPreservingPrinter.getOrCreateNodeText(t); 119 assertEquals(Arrays.asList("int"), 120 nodeText.getElements().stream().map(TextElement::expand).collect(Collectors.toList())); 121 } 122 123 @Test 124 public void checkNodeTextCreatedForSimpleImport() { 125 String code = "import a.b.c.D;"; 126 considerCode(code); 127 128 ImportDeclaration imp = (ImportDeclaration)cu.getChildNodes().get(0); 129 NodeText nodeText = LexicalPreservingPrinter.getOrCreateNodeText(imp); 130 assertEquals(Arrays.asList("import", " ", "a.b.c.D", ";", ""), 131 nodeText.getElements().stream().map(TextElement::expand).collect(Collectors.toList())); 132 } 133 134 @Test 135 public void checkNodeTextCreatedGenericType() { 136 String code = "class A {ParseResult<T> result;}"; 137 considerCode(code); 138 139 FieldDeclaration field = cu.getClassByName("A").get().getFieldByName("result").get(); 140 Node t = field.getCommonType(); 141 Node t2 = field.getVariable(0).getType(); 142 NodeText nodeText = LexicalPreservingPrinter.getOrCreateNodeText(field); 143 assertEquals(Arrays.asList("ParseResult", "<", "T", ">", " ", "result", ";"), 144 nodeText.getElements().stream().map(TextElement::expand).collect(Collectors.toList())); 145 } 146 147 @Test 148 public void checkNodeTextCreatedAnnotationDeclaration() { 149 String code = "public @interface ClassPreamble { String author(); }"; 150 considerCode(code); 151 152 AnnotationDeclaration ad = cu.getAnnotationDeclarationByName("ClassPreamble").get(); 153 NodeText nodeText = LexicalPreservingPrinter.getOrCreateNodeText(ad); 154 assertEquals(Arrays.asList("public", " ", "@", "interface", " ", "ClassPreamble", " ", "{", " ", "String author();", " ", "}", ""), 155 nodeText.getElements().stream().map(TextElement::expand).collect(Collectors.toList())); 156 } 157 158 @Test 159 public void checkNodeTextCreatedAnnotationMemberDeclaration() { 160 String code = "public @interface ClassPreamble { String author(); }"; 161 considerCode(code); 162 163 AnnotationDeclaration ad = cu.getAnnotationDeclarationByName("ClassPreamble").get(); 164 AnnotationMemberDeclaration md = (AnnotationMemberDeclaration)ad.getMember(0); 165 NodeText nodeText = LexicalPreservingPrinter.getOrCreateNodeText(md); 166 assertEquals(Arrays.asList("String", " ", "author", "(", ")", ";"), 167 nodeText.getElements().stream().map(TextElement::expand).collect(Collectors.toList())); 168 } 169 170 @Test 171 public void checkNodeTextCreatedAnnotationMemberDeclarationWithArrayType() { 172 String code = "public @interface ClassPreamble { String[] author(); }"; 173 considerCode(code); 174 175 AnnotationDeclaration ad = cu.getAnnotationDeclarationByName("ClassPreamble").get(); 176 AnnotationMemberDeclaration md = (AnnotationMemberDeclaration)ad.getMember(0); 177 NodeText nodeText = LexicalPreservingPrinter.getOrCreateNodeText(md); 178 assertEquals(Arrays.asList("String[]", " ", "author", "(", ")", ";"), 179 nodeText.getElements().stream().map(TextElement::expand).collect(Collectors.toList())); 180 } 181 182 @Test 183 public void checkNodeTextCreatedAnnotationMemberDeclarationArrayType() { 184 String code = "public @interface ClassPreamble { String[] author(); }"; 185 considerCode(code); 186 187 AnnotationDeclaration ad = cu.getAnnotationDeclarationByName("ClassPreamble").get(); 188 AnnotationMemberDeclaration md = (AnnotationMemberDeclaration)ad.getMember(0).asAnnotationMemberDeclaration(); 189 Type type = md.getType(); 190 NodeText nodeText = LexicalPreservingPrinter.getOrCreateNodeText(type); 191 assertEquals(Arrays.asList("String", "[", "]"), 192 nodeText.getElements().stream().map(TextElement::expand).collect(Collectors.toList())); 193 } 194 195 @Test 196 public void checkNodeTextCreatedAnnotationMemberDeclarationWithComment() throws IOException { 197 considerExample("AnnotationDeclaration_Example3_original"); 198 199 AnnotationMemberDeclaration md = (AnnotationMemberDeclaration)cu.getAnnotationDeclarationByName("ClassPreamble").get().getMember(5).asAnnotationMemberDeclaration(); 200 NodeText nodeText = LexicalPreservingPrinter.getOrCreateNodeText(md); 201 assertEquals(Arrays.asList("String[]", " ", "reviewers", "(", ")", ";"), 202 nodeText.getElements().stream().map(TextElement::expand).collect(Collectors.toList())); 203 } 204 205 @Test 206 public void checkNodeTextCreatedArrayCreationLevelWithoutExpression() throws IOException { 207 considerExpression("new int[]"); 208 209 ArrayCreationExpr arrayCreationExpr = (ArrayCreationExpr)expression.asArrayCreationExpr(); 210 ArrayCreationLevel arrayCreationLevel = arrayCreationExpr.getLevels().get(0); 211 NodeText nodeText = LexicalPreservingPrinter.getOrCreateNodeText(arrayCreationLevel); 212 assertEquals(Arrays.asList("[", "]"), 213 nodeText.getElements().stream().map(TextElement::expand).filter(e -> !e.isEmpty()).collect(Collectors.toList())); 214 } 215 216 @Test 217 public void checkNodeTextCreatedArrayCreationLevelWith() throws IOException { 218 considerExpression("new int[123]"); 219 220 ArrayCreationExpr arrayCreationExpr = (ArrayCreationExpr)expression.asArrayCreationExpr(); 221 ArrayCreationLevel arrayCreationLevel = arrayCreationExpr.getLevels().get(0); 222 NodeText nodeText = LexicalPreservingPrinter.getOrCreateNodeText(arrayCreationLevel); 223 assertEquals(Arrays.asList("[", "123", "]"), 224 nodeText.getElements().stream().map(TextElement::expand).filter(e -> !e.isEmpty()).collect(Collectors.toList())); 225 } 226 227 // 228 // Tests on findIndentation 229 // 230 231 @Test 232 public void findIndentationForAnnotationMemberDeclarationWithoutComment() throws IOException { 233 considerExample("AnnotationDeclaration_Example3_original"); 234 Node node = cu.getAnnotationDeclarationByName("ClassPreamble").get().getMember(4); 235 List<TokenTextElement> indentation = LexicalPreservingPrinter.findIndentation(node); 236 assertEquals(Arrays.asList(" ", " ", " "), indentation.stream().map(TokenTextElement::expand).collect(Collectors.toList())); 237 } 238 239 @Test 240 public void findIndentationForAnnotationMemberDeclarationWithComment() throws IOException { 241 considerExample("AnnotationDeclaration_Example3_original"); 242 Node node = cu.getAnnotationDeclarationByName("ClassPreamble").get().getMember(5); 243 List<TokenTextElement> indentation = LexicalPreservingPrinter.findIndentation(node); 244 assertEquals(Arrays.asList(" ", " ", " "), indentation.stream().map(TokenTextElement::expand).collect(Collectors.toList())); 245 } 246 247 // 248 // Tests on printing 249 // 250 251 @Test 252 public void printASuperSimpleCUWithoutChanges() { 253 String code = "class A {}"; 254 considerCode(code); 255 256 assertEquals(code, LexicalPreservingPrinter.print(cu)); 257 } 258 259 @Test 260 public void printASuperSimpleClassWithAFieldAdded() { 261 String code = "class A {}"; 262 considerCode(code); 263 264 ClassOrInterfaceDeclaration classA = cu.getClassByName("A").get(); 265 classA.addField("int", "myField"); 266 assertEquals("class A {" + EOL + " int myField;"+EOL+"}", LexicalPreservingPrinter.print(classA)); 267 } 268 269 @Test 270 public void printASuperSimpleClassWithoutChanges() { 271 String code = "class A {}"; 272 considerCode(code); 273 274 assertEquals(code, LexicalPreservingPrinter.print(cu.getClassByName("A").get())); 275 } 276 277 @Test 278 public void printASimpleCUWithoutChanges() { 279 String code = "class /*a comment*/ A {\t\t"+EOL+" int f;"+EOL+EOL+EOL+" void foo(int p ) { return 'z' \t; }}"; 280 considerCode(code); 281 282 assertEquals(code, LexicalPreservingPrinter.print(cu)); 283 assertEquals(code, LexicalPreservingPrinter.print(cu.getClassByName("A").get())); 284 assertEquals("void foo(int p ) { return 'z' \t; }", LexicalPreservingPrinter.print(cu.getClassByName("A").get().getMethodsByName("foo").get(0))); 285 } 286 287 @Test 288 public void printASimpleClassRemovingAField() { 289 String code = "class /*a comment*/ A {\t\t"+EOL+" int f;"+EOL+EOL+EOL+" void foo(int p ) { return 'z' \t; }}"; 290 considerCode(code); 291 292 ClassOrInterfaceDeclaration c = cu.getClassByName("A").get(); 293 c.getMembers().remove(0); 294 assertEquals("class /*a comment*/ A {\t\t"+ EOL + 295 EOL + 296 " void foo(int p ) { return 'z' \t; }}", LexicalPreservingPrinter.print(c)); 297 } 298 299 @Test 300 public void printASimpleMethodAddingAParameterToAMethodWithZeroParameters() { 301 String code = "class A { void foo() {} }"; 302 considerCode(code); 303 304 MethodDeclaration m = cu.getClassByName("A").get().getMethodsByName("foo").get(0); 305 m.addParameter("float", "p1"); 306 assertEquals("void foo(float p1) {}", LexicalPreservingPrinter.print(m)); 307 } 308 309 @Test 310 public void printASimpleMethodAddingAParameterToAMethodWithOneParameter() { 311 String code = "class A { void foo(char p1) {} }"; 312 considerCode(code); 313 314 MethodDeclaration m = cu.getClassByName("A").get().getMethodsByName("foo").get(0); 315 m.addParameter("float", "p2"); 316 assertEquals("void foo(char p1, float p2) {}", LexicalPreservingPrinter.print(m)); 317 } 318 319 @Test 320 public void printASimpleMethodRemovingAParameterToAMethodWithOneParameter() { 321 String code = "class A { void foo(float p1) {} }"; 322 considerCode(code); 323 324 MethodDeclaration m = cu.getClassByName("A").get().getMethodsByName("foo").get(0); 325 m.getParameters().remove(0); 326 assertEquals("void foo() {}", LexicalPreservingPrinter.print(m)); 327 } 328 329 @Test 330 public void printASimpleMethodRemovingParameterOneFromMethodWithTwoParameters() { 331 String code = "class A { void foo(char p1, int p2) {} }"; 332 considerCode(code); 333 334 MethodDeclaration m = cu.getClassByName("A").get().getMethodsByName("foo").get(0); 335 m.getParameters().remove(0); 336 assertEquals("void foo(int p2) {}", LexicalPreservingPrinter.print(m)); 337 } 338 339 @Test 340 public void printASimpleMethodRemovingParameterTwoFromMethodWithTwoParameters() { 341 String code = "class A { void foo(char p1, int p2) {} }"; 342 considerCode(code); 343 344 MethodDeclaration m = cu.getClassByName("A").get().getMethodsByName("foo").get(0); 345 m.getParameters().remove(1); 346 assertEquals("void foo(char p1) {}", LexicalPreservingPrinter.print(m)); 347 } 348 349 @Test 350 public void printASimpleMethodAddingAStatement() { 351 String code = "class A { void foo(char p1, int p2) {} }"; 352 considerCode(code); 353 354 Statement s = new ExpressionStmt(new BinaryExpr( 355 new IntegerLiteralExpr("10"), new IntegerLiteralExpr("2"), BinaryExpr.Operator.PLUS 356 )); 357 NodeList<Statement> stmts = cu.getClassByName("A").get().getMethodsByName("foo").get(0).getBody().get().getStatements(); 358 stmts.add(s); 359 MethodDeclaration m = cu.getClassByName("A").get().getMethodsByName("foo").get(0); 360 assertEquals("void foo(char p1, int p2) {"+EOL + 361 " 10 + 2;"+ EOL + 362 "}", LexicalPreservingPrinter.print(m)); 363 } 364 365 @Test 366 public void printASimpleImport() { 367 String code = "import a.b.c.D;"; 368 considerCode(code); 369 370 ImportDeclaration imp = (ImportDeclaration)cu.getChildNodes().get(0); 371 assertEquals("import a.b.c.D;", LexicalPreservingPrinter.print(imp)); 372 } 373 374 @Test 375 public void printAnotherImport() { 376 String code = "import com.github.javaparser.ast.CompilationUnit;"; 377 considerCode(code); 378 379 ImportDeclaration imp = (ImportDeclaration)cu.getChildNodes().get(0); 380 assertEquals("import com.github.javaparser.ast.CompilationUnit;", LexicalPreservingPrinter.print(imp)); 381 } 382 383 @Test 384 public void printAStaticImport() { 385 String code = "import static com.github.javaparser.ParseStart.*;"; 386 considerCode(code); 387 388 ImportDeclaration imp = (ImportDeclaration)cu.getChildNodes().get(0); 389 assertEquals("import static com.github.javaparser.ParseStart.*;", LexicalPreservingPrinter.print(imp)); 390 } 391 392 @Test 393 public void checkAnnidatedTypeParametersPrinting() { 394 String code = "class A { private final Stack<Iterator<Triple>> its = new Stack<Iterator<Triple>>(); }"; 395 considerCode(code); 396 assertEquals("class A { private final Stack<Iterator<Triple>> its = new Stack<Iterator<Triple>>(); }", LexicalPreservingPrinter.print(cu)); 397 } 398 399 @Test 400 public void printASingleCatch() { 401 String code = "class A {{try { doit(); } catch (Exception e) {}}}"; 402 considerCode(code); 403 404 assertEquals("class A {{try { doit(); } catch (Exception e) {}}}", LexicalPreservingPrinter.print(cu)); 405 } 406 407 @Test 408 public void printAMultiCatch() { 409 String code = "class A {{try { doit(); } catch (Exception | AssertionError e) {}}}"; 410 considerCode(code); 411 412 assertEquals("class A {{try { doit(); } catch (Exception | AssertionError e) {}}}", LexicalPreservingPrinter.print(cu)); 413 } 414 415 @Test 416 public void printASingleCatchType() { 417 String code = "class A {{try { doit(); } catch (Exception e) {}}}"; 418 considerCode(code); 419 InitializerDeclaration initializerDeclaration = (InitializerDeclaration)cu.getType(0).getMembers().get(0); 420 TryStmt tryStmt = (TryStmt)initializerDeclaration.getBody().getStatements().get(0); 421 CatchClause catchClause = tryStmt.getCatchClauses().get(0); 422 Type catchType = catchClause.getParameter().getType(); 423 424 assertEquals("Exception", LexicalPreservingPrinter.print(catchType)); 425 } 426 427 @Test 428 public void printUnionType() { 429 String code = "class A {{try { doit(); } catch (Exception | AssertionError e) {}}}"; 430 considerCode(code); 431 InitializerDeclaration initializerDeclaration = (InitializerDeclaration)cu.getType(0).getMembers().get(0); 432 TryStmt tryStmt = (TryStmt)initializerDeclaration.getBody().getStatements().get(0); 433 CatchClause catchClause = tryStmt.getCatchClauses().get(0); 434 UnionType unionType = (UnionType)catchClause.getParameter().getType(); 435 436 assertEquals("Exception | AssertionError", LexicalPreservingPrinter.print(unionType)); 437 } 438 439 @Test 440 public void printParameterHavingUnionType() { 441 String code = "class A {{try { doit(); } catch (Exception | AssertionError e) {}}}"; 442 considerCode(code); 443 InitializerDeclaration initializerDeclaration = (InitializerDeclaration)cu.getType(0).getMembers().get(0); 444 TryStmt tryStmt = (TryStmt)initializerDeclaration.getBody().getStatements().get(0); 445 CatchClause catchClause = tryStmt.getCatchClauses().get(0); 446 Parameter parameter = catchClause.getParameter(); 447 448 assertEquals("Exception | AssertionError e", LexicalPreservingPrinter.print(parameter)); 449 } 450 451 @Test 452 public void printLambaWithUntypedParams() { 453 String code = "class A {Function<String,String> f = a -> a;}"; 454 considerCode(code); 455 456 assertEquals("class A {Function<String,String> f = a -> a;}", LexicalPreservingPrinter.print(cu)); 457 } 458 459 @Test 460 public void printAModuleInfoSpecificKeywordUsedAsIdentifier1() { 461 considerCode("class module { }"); 462 463 cu.getClassByName("module").get().setName("xyz"); 464 465 assertEquals("class xyz { }", LexicalPreservingPrinter.print(cu)); 466 } 467 468 @Test 469 public void printAModuleInfoSpecificKeywordUsedAsIdentifier2() { 470 considerCode("class xyz { }"); 471 472 cu.getClassByName("xyz").get().setName("module"); 473 474 assertEquals("class module { }", LexicalPreservingPrinter.print(cu)); 475 } 476 477 // Issue 823: setPackageDeclaration on CU starting with a comment 478 @Test 479 public void reactToSetPackageDeclarationOnCuStartingWithComment() { 480 considerCode("// Hey, this is a comment\n" + 481 "\n" + 482 "\n" + 483 "// Another one\n" + 484 "\n" + 485 "class A {}"); 486 cu.setPackageDeclaration("org.javaparser.lexicalpreservation.examples"); 487 } 488 489 @Test 490 public void printLambdaIntersectionTypeAssignment() { 491 String code = "class A {" + EOL + 492 " void f() {" + EOL + 493 " Runnable r = (Runnable & Serializable) (() -> {});" + EOL + 494 " r = (Runnable & Serializable)() -> {};" + EOL + 495 " r = (Runnable & I)() -> {};" + EOL + 496 " }}"; 497 considerCode(code); 498 499 assertEquals(code, LexicalPreservingPrinter.print(cu)); 500 } 501 502 @Test 503 public void printLambdaIntersectionTypeReturn() { 504 String code = "class A {" + EOL 505 + " Object f() {" + EOL 506 + " return (Comparator<Map.Entry<K, V>> & Serializable)(c1, c2) -> c1.getKey().compareTo(c2.getKey()); " + EOL 507 + "}}"; 508 considerCode(code); 509 510 assertEquals(code, LexicalPreservingPrinter.print(cu)); 511 } 512 513 // See issue #855 514 @Test 515 public void handleOverrideAnnotation() { 516 String code = "public class TestPage extends Page {" + EOL + 517 EOL + 518 " protected void test() {}" + EOL + 519 EOL + 520 " @Override" + EOL + 521 " protected void initializePage() {}" + EOL + 522 "}"; 523 524 CompilationUnit cu = JavaParser.parse(code); 525 LexicalPreservingPrinter.setup(cu); 526 527 cu.getTypes() 528 .forEach(type -> type.getMembers() 529 .forEach(member -> { 530 if (member instanceof MethodDeclaration) { 531 MethodDeclaration methodDeclaration = (MethodDeclaration) member; 532 if (!methodDeclaration.getAnnotationByName("Override").isPresent()) { 533 methodDeclaration.addAnnotation("Override"); 534 } 535 } 536 })); 537 assertEquals("public class TestPage extends Page {" + EOL + 538 EOL + 539 " @Override()" + EOL + 540 " protected void test() {}" + EOL + 541 EOL + 542 " @Override" + EOL + 543 " protected void initializePage() {}" + EOL + 544 "}", LexicalPreservingPrinter.print(cu)); 545 } 546 547 @Test 548 public void preserveSpaceAsIsForASimpleClassWithMoreFormatting() throws IOException { 549 considerExample("ASimpleClassWithMoreFormatting"); 550 assertEquals(readExample("ASimpleClassWithMoreFormatting"), LexicalPreservingPrinter.print(cu)); 551 } 552 553 @Test 554 public void renameASimpleClassWithMoreFormatting() throws IOException { 555 considerExample("ASimpleClassWithMoreFormatting"); 556 557 cu.getClassByName("ASimpleClass").get() 558 .setName("MyRenamedClass"); 559 assertEquals(readExample("ASimpleClassWithMoreFormatting_step1"), LexicalPreservingPrinter.print(cu)); 560 } 561 562 @Test 563 public void theLexicalPreservationStringForAnAddedMethodShouldBeIndented() throws IOException { 564 considerExample("ASimpleClassWithMoreFormatting"); 565 566 cu.getClassByName("ASimpleClass").get() 567 .setName("MyRenamedClass"); 568 MethodDeclaration setter = cu 569 .getClassByName("MyRenamedClass").get() 570 .addMethod("setAField", Modifier.PUBLIC); 571 assertEquals("public void setAField() {" + EOL + 572 " }", LexicalPreservingPrinter.print(setter)); 573 } 574 575 @Test 576 public void addMethodToASimpleClassWithMoreFormatting() throws IOException { 577 considerExample("ASimpleClassWithMoreFormatting"); 578 579 cu.getClassByName("ASimpleClass").get() 580 .setName("MyRenamedClass"); 581 MethodDeclaration setter = cu 582 .getClassByName("MyRenamedClass").get() 583 .addMethod("setAField", Modifier.PUBLIC); 584 assertEquals(readExample("ASimpleClassWithMoreFormatting_step2"), LexicalPreservingPrinter.print(cu)); 585 } 586 587 @Test 588 public void addingParameterToAnAddedMethodInASimpleClassWithMoreFormatting() throws IOException { 589 considerExample("ASimpleClassWithMoreFormatting"); 590 591 cu.getClassByName("ASimpleClass").get() 592 .setName("MyRenamedClass"); 593 MethodDeclaration setter = cu 594 .getClassByName("MyRenamedClass").get() 595 .addMethod("setAField", Modifier.PUBLIC); 596 setter.addParameter("boolean", "aField"); 597 assertEquals(readExample("ASimpleClassWithMoreFormatting_step3"), LexicalPreservingPrinter.print(cu)); 598 } 599 600 @Test 601 public void findIndentationOfEmptyMethod() throws IOException { 602 considerExample("ASimpleClassWithMoreFormatting_step3"); 603 604 MethodDeclaration setter = cu.getClassByName("MyRenamedClass").get() 605 .getMethodsByName("setAField").get(0); 606 assertEquals(4, LexicalPreservingPrinter.findIndentation(setter).size()); 607 assertEquals(4, LexicalPreservingPrinter.findIndentation(setter.getBody().get()).size()); 608 } 609 610 @Test 611 public void findIndentationOfMethodWithStatements() throws IOException { 612 considerExample("ASimpleClassWithMoreFormatting_step4"); 613 614 MethodDeclaration setter = cu.getClassByName("MyRenamedClass").get() 615 .getMethodsByName("setAField").get(0); 616 assertEquals(4, LexicalPreservingPrinter.findIndentation(setter).size()); 617 assertEquals(4, LexicalPreservingPrinter.findIndentation(setter.getBody().get()).size()); 618 assertEquals(8, LexicalPreservingPrinter.findIndentation(setter.getBody().get().getStatement(0)).size()); 619 } 620 621 @Test 622 public void addingStatementToAnAddedMethodInASimpleClassWithMoreFormatting() throws IOException { 623 considerExample("ASimpleClassWithMoreFormatting"); 624 625 cu.getClassByName("ASimpleClass").get() 626 .setName("MyRenamedClass"); 627 MethodDeclaration setter = cu 628 .getClassByName("MyRenamedClass").get() 629 .addMethod("setAField", Modifier.PUBLIC); 630 setter.addParameter("boolean", "aField"); 631 setter.getBody().get().getStatements().add(new ExpressionStmt( 632 new AssignExpr( 633 new FieldAccessExpr(new ThisExpr(),"aField"), 634 new NameExpr("aField"), 635 AssignExpr.Operator.ASSIGN 636 ))); 637 assertEquals(readExample("ASimpleClassWithMoreFormatting_step4"), LexicalPreservingPrinter.print(cu)); 638 } 639 640 @Test 641 public void addingStatementToAnAddedMethodInASimpleClassWithMoreFormattingFromStep3() throws IOException { 642 considerExample("ASimpleClassWithMoreFormatting_step3"); 643 644 MethodDeclaration setter = cu.getClassByName("MyRenamedClass").get() 645 .getMethodsByName("setAField").get(0); 646 setter.getBody().get().getStatements().add(new ExpressionStmt( 647 new AssignExpr( 648 new FieldAccessExpr(new ThisExpr(),"aField"), 649 new NameExpr("aField"), 650 AssignExpr.Operator.ASSIGN 651 ))); 652 assertEquals(readExample("ASimpleClassWithMoreFormatting_step4"), LexicalPreservingPrinter.print(cu)); 653 } 654 655 @Test 656 public void nodeTextForMethod() throws IOException { 657 considerExample("ASimpleClassWithMoreFormatting_step4"); 658 659 MethodDeclaration setter = cu.getClassByName("MyRenamedClass").get() 660 .getMethodsByName("setAField").get(0); 661 NodeText nodeText; 662 663 nodeText = getTextForNode(setter); 664 int index = 0; 665 assertTrue(nodeText.getElements().get(index++).isToken(GeneratedJavaParserConstants.PUBLIC)); 666 assertTrue(nodeText.getElements().get(index++).isToken(GeneratedJavaParserConstants.SPACE)); 667 assertTrue(nodeText.getElements().get(index++).isChildOfClass(VoidType.class)); 668 assertTrue(nodeText.getElements().get(index++).isToken(GeneratedJavaParserConstants.SPACE)); 669 assertTrue(nodeText.getElements().get(index++).isChildOfClass(SimpleName.class)); 670 assertTrue(nodeText.getElements().get(index++).isToken(GeneratedJavaParserConstants.LPAREN)); 671 assertTrue(nodeText.getElements().get(index++).isChildOfClass(Parameter.class)); 672 assertTrue(nodeText.getElements().get(index++).isToken(GeneratedJavaParserConstants.RPAREN)); 673 assertTrue(nodeText.getElements().get(index++).isToken(GeneratedJavaParserConstants.SPACE)); 674 assertTrue(nodeText.getElements().get(index++).isChildOfClass(BlockStmt.class)); 675 assertEquals(index, nodeText.getElements().size()); 676 677 nodeText = getTextForNode(setter.getBody().get()); 678 index = 0; 679 assertTrue(nodeText.getElements().get(index++).isToken(GeneratedJavaParserConstants.LBRACE)); 680 assertTrue(nodeText.getElements().get(index++).isNewline()); 681 assertTrue(nodeText.getElements().get(index++).isToken(GeneratedJavaParserConstants.SPACE)); 682 assertTrue(nodeText.getElements().get(index++).isToken(GeneratedJavaParserConstants.SPACE)); 683 assertTrue(nodeText.getElements().get(index++).isToken(GeneratedJavaParserConstants.SPACE)); 684 assertTrue(nodeText.getElements().get(index++).isToken(GeneratedJavaParserConstants.SPACE)); 685 assertTrue(nodeText.getElements().get(index++).isToken(GeneratedJavaParserConstants.SPACE)); 686 assertTrue(nodeText.getElements().get(index++).isToken(GeneratedJavaParserConstants.SPACE)); 687 assertTrue(nodeText.getElements().get(index++).isToken(GeneratedJavaParserConstants.SPACE)); 688 assertTrue(nodeText.getElements().get(index++).isToken(GeneratedJavaParserConstants.SPACE)); 689 assertTrue(nodeText.getElements().get(index++).isChildOfClass(ExpressionStmt.class)); 690 assertTrue(nodeText.getElements().get(index++).isNewline()); 691 assertTrue(nodeText.getElements().get(index++).isToken(GeneratedJavaParserConstants.SPACE)); 692 assertTrue(nodeText.getElements().get(index++).isToken(GeneratedJavaParserConstants.SPACE)); 693 assertTrue(nodeText.getElements().get(index++).isToken(GeneratedJavaParserConstants.SPACE)); 694 assertTrue(nodeText.getElements().get(index++).isToken(GeneratedJavaParserConstants.SPACE)); 695 assertTrue(nodeText.getElements().get(index++).isToken(GeneratedJavaParserConstants.RBRACE)); 696 assertEquals(index, nodeText.getElements().size()); 697 698 nodeText = getTextForNode(setter.getBody().get().getStatement(0)); 699 index = 0; 700 assertTrue(nodeText.getElements().get(index++).isChildOfClass(AssignExpr.class)); 701 assertTrue(nodeText.getElements().get(index++).isToken(GeneratedJavaParserConstants.SEMICOLON)); 702 assertEquals(index, nodeText.getElements().size()); 703 } 704 705 @Test 706 public void nodeTextForModifiedMethod() throws IOException { 707 considerExample("ASimpleClassWithMoreFormatting_step3"); 708 709 MethodDeclaration setter = cu.getClassByName("MyRenamedClass").get() 710 .getMethodsByName("setAField").get(0); 711 setter.getBody().get().getStatements().add(new ExpressionStmt( 712 new AssignExpr( 713 new FieldAccessExpr(new ThisExpr(),"aField"), 714 new NameExpr("aField"), 715 AssignExpr.Operator.ASSIGN 716 ))); 717 NodeText nodeText; 718 719 nodeText = getTextForNode(setter); 720 int index = 0; 721 assertTrue(nodeText.getElements().get(index++).isToken(GeneratedJavaParserConstants.PUBLIC)); 722 assertTrue(nodeText.getElements().get(index++).isToken(GeneratedJavaParserConstants.SPACE)); 723 assertTrue(nodeText.getElements().get(index++).isChildOfClass(VoidType.class)); 724 assertTrue(nodeText.getElements().get(index++).isToken(GeneratedJavaParserConstants.SPACE)); 725 assertTrue(nodeText.getElements().get(index++).isChildOfClass(SimpleName.class)); 726 assertTrue(nodeText.getElements().get(index++).isToken(GeneratedJavaParserConstants.LPAREN)); 727 assertTrue(nodeText.getElements().get(index++).isChildOfClass(Parameter.class)); 728 assertTrue(nodeText.getElements().get(index++).isToken(GeneratedJavaParserConstants.RPAREN)); 729 assertTrue(nodeText.getElements().get(index++).isToken(GeneratedJavaParserConstants.SPACE)); 730 assertTrue(nodeText.getElements().get(index++).isChildOfClass(BlockStmt.class)); 731 assertEquals(index, nodeText.getElements().size()); 732 733 nodeText = getTextForNode(setter.getBody().get()); 734 index = 0; 735 assertTrue(nodeText.getElements().get(index++).isToken(GeneratedJavaParserConstants.LBRACE)); 736 assertTrue(nodeText.getElements().get(index++).isNewline()); 737 assertTrue(nodeText.getElements().get(index++).isToken(GeneratedJavaParserConstants.SPACE)); 738 assertTrue(nodeText.getElements().get(index++).isToken(GeneratedJavaParserConstants.SPACE)); 739 assertTrue(nodeText.getElements().get(index++).isToken(GeneratedJavaParserConstants.SPACE)); 740 assertTrue(nodeText.getElements().get(index++).isToken(GeneratedJavaParserConstants.SPACE)); 741 assertTrue(nodeText.getElements().get(index++).isToken(GeneratedJavaParserConstants.SPACE)); 742 assertTrue(nodeText.getElements().get(index++).isToken(GeneratedJavaParserConstants.SPACE)); 743 assertTrue(nodeText.getElements().get(index++).isToken(GeneratedJavaParserConstants.SPACE)); 744 assertTrue(nodeText.getElements().get(index++).isToken(GeneratedJavaParserConstants.SPACE)); 745 assertTrue(nodeText.getElements().get(index++).isChildOfClass(ExpressionStmt.class)); 746 assertTrue(nodeText.getElements().get(index++).isNewline()); 747 assertTrue(nodeText.getElements().get(index++).isToken(GeneratedJavaParserConstants.SPACE)); 748 assertTrue(nodeText.getElements().get(index++).isToken(GeneratedJavaParserConstants.SPACE)); 749 assertTrue(nodeText.getElements().get(index++).isToken(GeneratedJavaParserConstants.SPACE)); 750 assertTrue(nodeText.getElements().get(index++).isToken(GeneratedJavaParserConstants.SPACE)); 751 assertTrue(nodeText.getElements().get(index++).isToken(GeneratedJavaParserConstants.RBRACE)); 752 assertEquals(index, nodeText.getElements().size()); 753 754 nodeText = LexicalPreservingPrinter.getOrCreateNodeText(setter.getBody().get().getStatement(0)); 755 index = 0; 756 assertTrue(nodeText.getElements().get(index++).isChildOfClass(AssignExpr.class)); 757 assertTrue(nodeText.getElements().get(index++).isToken(GeneratedJavaParserConstants.SEMICOLON)); 758 assertEquals(index, nodeText.getElements().size()); 759 } 760 761 // See issue #926 762 @Test 763 public void addASecondStatementToExistingMethod() throws IOException { 764 considerExample("MethodWithOneStatement"); 765 766 MethodDeclaration methodDeclaration = cu.getType(0).getMethodsByName("someMethod").get(0); 767 methodDeclaration.getBody().get().getStatements().add(new ExpressionStmt( 768 new VariableDeclarationExpr( 769 new VariableDeclarator( 770 JavaParser.parseClassOrInterfaceType("String"), 771 "test2", 772 new StringLiteralExpr(""))) 773 )); 774 assertEquals("public void someMethod() {" + EOL 775 + " String test = \"\";" + EOL 776 + " String test2 = \"\";" + EOL 777 + " }", LexicalPreservingPrinter.print(methodDeclaration)); 778 } 779 780 // See issue #866 781 @Test 782 public void moveOverrideAnnotations() { 783 String code = "public class TestPage extends Page {" + EOL + 784 EOL + 785 " protected void test() {}" + EOL + 786 EOL + 787 " protected @Override void initializePage() {}" + EOL + 788 "}"; 789 790 CompilationUnit cu = JavaParser.parse(code); 791 LexicalPreservingPrinter.setup(cu); 792 793 cu.getTypes() 794 .forEach(type -> { 795 type.getMembers() 796 .forEach(member -> { 797 member.ifMethodDeclaration(methodDeclaration -> { 798 if (methodDeclaration.getAnnotationByName("Override").isPresent()) { 799 800 while (methodDeclaration.getAnnotations().isNonEmpty()) { 801 AnnotationExpr annotationExpr = methodDeclaration.getAnnotations().get(0); 802 annotationExpr.remove(); 803 } 804 805 methodDeclaration.addMarkerAnnotation("Override"); 806 } 807 }); 808 }); 809 }); 810 assertEquals("public class TestPage extends Page {" + EOL + 811 EOL + 812 " protected void test() {}" + EOL + 813 EOL + 814 " @Override" + EOL + 815 " protected void initializePage() {}" + EOL + 816 "}", LexicalPreservingPrinter.print(cu)); 817 } 818 819 // See issue #866 820 @Test 821 public void moveOrAddOverrideAnnotations() { 822 String code = "public class TestPage extends Page {" + EOL + 823 EOL + 824 " protected void test() {}" + EOL + 825 EOL + 826 " protected @Override void initializePage() {}" + EOL + 827 "}"; 828 829 CompilationUnit cu = JavaParser.parse(code); 830 LexicalPreservingPrinter.setup(cu); 831 832 cu.getTypes() 833 .forEach(type -> { 834 type.getMembers() 835 .forEach(member -> { 836 if (member instanceof MethodDeclaration) { 837 MethodDeclaration methodDeclaration = (MethodDeclaration) member; 838 if (methodDeclaration.getAnnotationByName("Override").isPresent()) { 839 840 while (methodDeclaration.getAnnotations().isNonEmpty()) { 841 AnnotationExpr annotationExpr = methodDeclaration.getAnnotations().get(0); 842 annotationExpr.remove(); 843 } 844 } 845 methodDeclaration.addMarkerAnnotation("Override"); 846 } 847 }); 848 }); 849 assertEquals("public class TestPage extends Page {" + EOL + 850 EOL + 851 " @Override" + EOL + 852 " protected void test() {}" + EOL + 853 EOL + 854 " @Override" + EOL + 855 " protected void initializePage() {}" + EOL + 856 "}", LexicalPreservingPrinter.print(cu)); 857 } 858 859 // See issue #865 860 @Test 861 public void handleAddingMarkerAnnotation() { 862 String code = "public class TestPage extends Page {" + EOL + 863 EOL + 864 " protected void test() {}" + EOL + 865 EOL + 866 " @Override" + EOL + 867 " protected void initializePage() {}" + EOL + 868 "}"; 869 870 CompilationUnit cu = JavaParser.parse(code); 871 LexicalPreservingPrinter.setup(cu); 872 873 cu.getTypes() 874 .forEach(type -> { 875 type.getMembers() 876 .forEach(member -> { 877 if (member instanceof MethodDeclaration) { 878 MethodDeclaration methodDeclaration = (MethodDeclaration) member; 879 if (!methodDeclaration.getAnnotationByName("Override").isPresent()) { 880 methodDeclaration.addMarkerAnnotation("Override"); 881 } 882 } 883 }); 884 }); 885 assertEquals("public class TestPage extends Page {" + EOL + 886 EOL + 887 " @Override" + EOL + 888 " protected void test() {}" + EOL + 889 EOL + 890 " @Override" + EOL + 891 " protected void initializePage() {}" + EOL + 892 "}", LexicalPreservingPrinter.print(cu)); 893 } 894 895 // See issue #865 896 @Test 897 public void handleOverrideMarkerAnnotation() { 898 String code = "public class TestPage extends Page {" + EOL + 899 EOL + 900 " protected void test() {}" + EOL + 901 EOL + 902 " protected void initializePage() {}" + EOL + 903 "}"; 904 905 CompilationUnit cu = JavaParser.parse(code); 906 LexicalPreservingPrinter.setup(cu); 907 908 cu.getTypes() 909 .forEach(type -> type.getMembers() 910 .forEach(member -> 911 member.ifMethodDeclaration(methodDeclaration -> methodDeclaration.addMarkerAnnotation("Override") 912 ))); 913 assertEquals("public class TestPage extends Page {" + EOL + 914 EOL + 915 " @Override" + EOL + 916 " protected void test() {}" + EOL + 917 EOL + 918 " @Override" + EOL + 919 " protected void initializePage() {}" + EOL + 920 "}", LexicalPreservingPrinter.print(cu)); 921 } 922 923 // See issue #865 924 @Test 925 public void handleOverrideAnnotationAlternative() { 926 String code = "public class TestPage extends Page {" + EOL + 927 EOL + 928 " protected void test() {}" + EOL + 929 EOL + 930 " protected void initializePage() {}" + EOL + 931 "}"; 932 933 CompilationUnit cu = JavaParser.parse(code); 934 LexicalPreservingPrinter.setup(cu); 935 936 cu.getTypes() 937 .forEach(type -> type.getMembers() 938 .forEach(member -> member.ifMethodDeclaration(methodDeclaration -> methodDeclaration.addAnnotation("Override")))); 939 assertEquals("public class TestPage extends Page {" + EOL + 940 EOL + 941 " @Override()" + EOL + 942 " protected void test() {}" + EOL + 943 EOL + 944 " @Override()" + EOL + 945 " protected void initializePage() {}" + EOL + 946 "}", LexicalPreservingPrinter.print(cu)); 947 } 948 949 @Test 950 public void invokeModifierVisitor() { 951 String code = "class A {" + EOL 952 + " Object f() {" + EOL 953 + " return (Comparator<Map.Entry<K, V>> & Serializable)(c1, c2) -> c1.getKey().compareTo(c2.getKey()); " + EOL 954 + "}}"; 955 CompilationUnit cu = JavaParser.parse(code); 956 LexicalPreservingPrinter.setup(cu); 957 cu.accept(new ModifierVisitor<>(), null); 958 } 959 960 @Test 961 public void handleDeprecatedAnnotationFinalClass() { 962 String code = "public final class A {}"; 963 964 CompilationUnit cu = JavaParser.parse(code); 965 LexicalPreservingPrinter.setup(cu); 966 967 cu.getTypes().forEach(type -> type.addAndGetAnnotation(Deprecated.class)); 968 969 assertEquals("@Deprecated()" + EOL + 970 "public final class A {}" , LexicalPreservingPrinter.print(cu)); 971 972 } 973 974 @Test 975 public void handleDeprecatedAnnotationAbstractClass() { 976 String code = "public abstract class A {}"; 977 978 CompilationUnit cu = JavaParser.parse(code); 979 LexicalPreservingPrinter.setup(cu); 980 981 cu.getTypes().forEach(type -> type.addAndGetAnnotation(Deprecated.class)); 982 983 assertEquals("@Deprecated()" + EOL + 984 "public abstract class A {}" , LexicalPreservingPrinter.print(cu)); 985 } 986 987 @Test 988 public void issue1244() { 989 String code = "public class Foo {" + EOL + EOL 990 + "// Some comment" + EOL + EOL // does work with only one \n 991 + "public void writeExternal() {}" + EOL + "}"; 992 CompilationUnit originalCu = JavaParser.parse(code); 993 CompilationUnit cu = LexicalPreservingPrinter.setup(originalCu); 994 995 cu.findAll(ClassOrInterfaceDeclaration.class).stream().forEach(c -> { 996 List<MethodDeclaration> methods = c.getMethodsByName("writeExternal"); 997 for (MethodDeclaration method : methods) { 998 c.remove(method); 999 } 1000 }); 1001 assertEqualsNoEol("public class Foo {\n" + 1002 "// Some comment\n\n" + 1003 "}", LexicalPreservingPrinter.print(cu)); 1004 } 1005 1006 static class AddFooCallModifierVisitor extends ModifierVisitor<Void> { 1007 @Override 1008 public Visitable visit(MethodCallExpr n, Void arg) { 1009 // Add a call to foo() on every found method call 1010 return new MethodCallExpr(n, "foo"); 1011 } 1012 } 1013 1014 // See issue 1277 1015 @Test 1016 public void testInvokeModifierVisitor() throws IOException { 1017 String code = "class A {" + EOL + 1018 " public String message = \"hello\";" + EOL + 1019 " void bar() {" + EOL + 1020 " System.out.println(\"hello\");" + EOL + 1021 " }" + EOL + 1022 "}"; 1023 1024 CompilationUnit cu = JavaParser.parse(code); 1025 LexicalPreservingPrinter.setup(cu); 1026 cu.accept(new AddFooCallModifierVisitor(), null); 1027 } 1028 1029 static class CallModifierVisitor extends ModifierVisitor<Void> { 1030 @Override 1031 public Visitable visit(MethodCallExpr n, Void arg) { 1032 // Add a call to foo() on every found method call 1033 return new MethodCallExpr(n.clone(), "foo"); 1034 } 1035 } 1036 1037 @Test 1038 public void invokeModifierVisitorIssue1297() { 1039 String code = "class A {" + EOL + 1040 " public void bar() {" + EOL + 1041 " System.out.println(\"hello\");" + EOL + 1042 " System.out.println(\"hello\");" + EOL + 1043 " // comment" + EOL + 1044 " }" + EOL + 1045 "}"; 1046 1047 CompilationUnit cu = JavaParser.parse(code); 1048 LexicalPreservingPrinter.setup(cu); 1049 cu.accept(new CallModifierVisitor(), null); 1050 } 1051 } 1052