001/////////////////////////////////////////////////////////////////////////////////////////////// 002// checkstyle: Checks Java source code and other text files for adherence to a set of rules. 003// Copyright (C) 2001-2024 the original author or authors. 004// 005// This library is free software; you can redistribute it and/or 006// modify it under the terms of the GNU Lesser General Public 007// License as published by the Free Software Foundation; either 008// version 2.1 of the License, or (at your option) any later version. 009// 010// This library is distributed in the hope that it will be useful, 011// but WITHOUT ANY WARRANTY; without even the implied warranty of 012// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 013// Lesser General Public License for more details. 014// 015// You should have received a copy of the GNU Lesser General Public 016// License along with this library; if not, write to the Free Software 017// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 018/////////////////////////////////////////////////////////////////////////////////////////////// 019 020package com.puppycrawl.tools.checkstyle; 021 022import java.util.ArrayList; 023import java.util.Collections; 024import java.util.Iterator; 025import java.util.List; 026import java.util.Optional; 027import java.util.Queue; 028import java.util.concurrent.ConcurrentLinkedQueue; 029import java.util.stream.Collectors; 030 031import org.antlr.v4.runtime.BufferedTokenStream; 032import org.antlr.v4.runtime.CommonTokenStream; 033import org.antlr.v4.runtime.ParserRuleContext; 034import org.antlr.v4.runtime.Token; 035import org.antlr.v4.runtime.tree.ParseTree; 036import org.antlr.v4.runtime.tree.TerminalNode; 037 038import com.puppycrawl.tools.checkstyle.api.TokenTypes; 039import com.puppycrawl.tools.checkstyle.grammar.java.JavaLanguageLexer; 040import com.puppycrawl.tools.checkstyle.grammar.java.JavaLanguageParser; 041import com.puppycrawl.tools.checkstyle.grammar.java.JavaLanguageParserBaseVisitor; 042import com.puppycrawl.tools.checkstyle.utils.TokenUtil; 043 044/** 045 * Visitor class used to build Checkstyle's Java AST from the parse tree produced by 046 * {@link JavaLanguageParser}. In each {@code visit...} method, we visit the children of a node 047 * (which correspond to subrules) or create terminal nodes (tokens), and return a subtree as a 048 * result. 049 * 050 * <p>Example:</p> 051 * 052 * <p>The following package declaration:</p> 053 * <pre> 054 * package com.puppycrawl.tools.checkstyle; 055 * </pre> 056 * 057 * <p> 058 * Will be parsed by the {@code packageDeclaration} rule from {@code JavaLanguageParser.g4}: 059 * </p> 060 * <pre> 061 * packageDeclaration 062 * : annotations[true] LITERAL_PACKAGE qualifiedName SEMI 063 * ; 064 * </pre> 065 * 066 * <p> 067 * We override the {@code visitPackageDeclaration} method generated by ANTLR in 068 * {@link JavaLanguageParser} at 069 * {@link JavaAstVisitor#visitPackageDeclaration(JavaLanguageParser.PackageDeclarationContext)} 070 * to create a subtree based on the subrules and tokens found in the {@code packageDeclaration} 071 * subrule accordingly, thus producing the following AST: 072 * </p> 073 * <pre> 074 * PACKAGE_DEF -> package 075 * |--ANNOTATIONS -> ANNOTATIONS 076 * |--DOT -> . 077 * | |--DOT -> . 078 * | | |--DOT -> . 079 * | | | |--IDENT -> com 080 * | | | `--IDENT -> puppycrawl 081 * | | `--IDENT -> tools 082 * | `--IDENT -> checkstyle 083 * `--SEMI -> ; 084 * </pre> 085 * 086 * <p> 087 * See <a href="https://github.com/checkstyle/checkstyle/pull/10434">#10434</a> 088 * for a good example of how 089 * to make changes to Checkstyle's grammar and AST. 090 * </p> 091 * 092 * <p> 093 * The order of {@code visit...} methods in {@code JavaAstVisitor.java} and production rules in 094 * {@code JavaLanguageParser.g4} should be consistent to ease maintenance. 095 * </p> 096 */ 097public final class JavaAstVisitor extends JavaLanguageParserBaseVisitor<DetailAstImpl> { 098 099 /** String representation of the left shift operator. */ 100 private static final String LEFT_SHIFT = "<<"; 101 102 /** String representation of the unsigned right shift operator. */ 103 private static final String UNSIGNED_RIGHT_SHIFT = ">>>"; 104 105 /** String representation of the right shift operator. */ 106 private static final String RIGHT_SHIFT = ">>"; 107 108 /** 109 * The tokens here are technically expressions, but should 110 * not return an EXPR token as their root. 111 */ 112 private static final int[] EXPRESSIONS_WITH_NO_EXPR_ROOT = { 113 TokenTypes.CTOR_CALL, 114 TokenTypes.SUPER_CTOR_CALL, 115 TokenTypes.LAMBDA, 116 }; 117 118 /** Token stream to check for hidden tokens. */ 119 private final BufferedTokenStream tokens; 120 121 /** 122 * Constructs a JavaAstVisitor with given token stream. 123 * 124 * @param tokenStream the token stream to check for hidden tokens 125 */ 126 public JavaAstVisitor(CommonTokenStream tokenStream) { 127 tokens = tokenStream; 128 } 129 130 @Override 131 public DetailAstImpl visitCompilationUnit(JavaLanguageParser.CompilationUnitContext ctx) { 132 final DetailAstImpl compilationUnit; 133 // 'EOF' token is always present; therefore if we only have one child, we have an empty file 134 final boolean isEmptyFile = ctx.children.size() == 1; 135 if (isEmptyFile) { 136 compilationUnit = null; 137 } 138 else { 139 compilationUnit = createImaginary(TokenTypes.COMPILATION_UNIT); 140 // last child is 'EOF', we do not include this token in AST 141 processChildren(compilationUnit, ctx.children.subList(0, ctx.children.size() - 1)); 142 } 143 return compilationUnit; 144 } 145 146 @Override 147 public DetailAstImpl visitPackageDeclaration( 148 JavaLanguageParser.PackageDeclarationContext ctx) { 149 final DetailAstImpl packageDeclaration = 150 create(TokenTypes.PACKAGE_DEF, (Token) ctx.LITERAL_PACKAGE().getPayload()); 151 packageDeclaration.addChild(visit(ctx.annotations())); 152 packageDeclaration.addChild(visit(ctx.qualifiedName())); 153 packageDeclaration.addChild(create(ctx.SEMI())); 154 return packageDeclaration; 155 } 156 157 @Override 158 public DetailAstImpl visitImportDec(JavaLanguageParser.ImportDecContext ctx) { 159 final DetailAstImpl importRoot = create(ctx.start); 160 161 // Static import 162 final TerminalNode literalStaticNode = ctx.LITERAL_STATIC(); 163 if (literalStaticNode != null) { 164 importRoot.setType(TokenTypes.STATIC_IMPORT); 165 importRoot.addChild(create(literalStaticNode)); 166 } 167 168 // Handle star imports 169 final boolean isStarImport = ctx.STAR() != null; 170 if (isStarImport) { 171 final DetailAstImpl dot = create(ctx.DOT()); 172 dot.addChild(visit(ctx.qualifiedName())); 173 dot.addChild(create(ctx.STAR())); 174 importRoot.addChild(dot); 175 } 176 else { 177 importRoot.addChild(visit(ctx.qualifiedName())); 178 } 179 180 importRoot.addChild(create(ctx.SEMI())); 181 return importRoot; 182 } 183 184 @Override 185 public DetailAstImpl visitSingleSemiImport(JavaLanguageParser.SingleSemiImportContext ctx) { 186 return create(ctx.SEMI()); 187 } 188 189 @Override 190 public DetailAstImpl visitTypeDeclaration(JavaLanguageParser.TypeDeclarationContext ctx) { 191 final DetailAstImpl typeDeclaration; 192 if (ctx.type == null) { 193 typeDeclaration = create(ctx.semi.get(0)); 194 ctx.semi.subList(1, ctx.semi.size()) 195 .forEach(semi -> addLastSibling(typeDeclaration, create(semi))); 196 } 197 else { 198 typeDeclaration = visit(ctx.type); 199 } 200 return typeDeclaration; 201 } 202 203 @Override 204 public DetailAstImpl visitModifier(JavaLanguageParser.ModifierContext ctx) { 205 return flattenedTree(ctx); 206 } 207 208 @Override 209 public DetailAstImpl visitVariableModifier(JavaLanguageParser.VariableModifierContext ctx) { 210 return flattenedTree(ctx); 211 } 212 213 @Override 214 public DetailAstImpl visitClassDeclaration(JavaLanguageParser.ClassDeclarationContext ctx) { 215 return createTypeDeclaration(ctx, TokenTypes.CLASS_DEF, ctx.mods); 216 } 217 218 @Override 219 public DetailAstImpl visitRecordDeclaration(JavaLanguageParser.RecordDeclarationContext ctx) { 220 return createTypeDeclaration(ctx, TokenTypes.RECORD_DEF, ctx.mods); 221 } 222 223 @Override 224 public DetailAstImpl visitRecordComponentsList( 225 JavaLanguageParser.RecordComponentsListContext ctx) { 226 final DetailAstImpl lparen = create(ctx.LPAREN()); 227 228 // We make a "RECORD_COMPONENTS" node whether components exist or not 229 if (ctx.recordComponents() == null) { 230 addLastSibling(lparen, createImaginary(TokenTypes.RECORD_COMPONENTS)); 231 } 232 else { 233 addLastSibling(lparen, visit(ctx.recordComponents())); 234 } 235 addLastSibling(lparen, create(ctx.RPAREN())); 236 return lparen; 237 } 238 239 @Override 240 public DetailAstImpl visitRecordComponents(JavaLanguageParser.RecordComponentsContext ctx) { 241 final DetailAstImpl recordComponents = createImaginary(TokenTypes.RECORD_COMPONENTS); 242 processChildren(recordComponents, ctx.children); 243 return recordComponents; 244 } 245 246 @Override 247 public DetailAstImpl visitRecordComponent(JavaLanguageParser.RecordComponentContext ctx) { 248 final DetailAstImpl recordComponent = createImaginary(TokenTypes.RECORD_COMPONENT_DEF); 249 processChildren(recordComponent, ctx.children); 250 return recordComponent; 251 } 252 253 @Override 254 public DetailAstImpl visitLastRecordComponent( 255 JavaLanguageParser.LastRecordComponentContext ctx) { 256 final DetailAstImpl recordComponent = createImaginary(TokenTypes.RECORD_COMPONENT_DEF); 257 processChildren(recordComponent, ctx.children); 258 return recordComponent; 259 } 260 261 @Override 262 public DetailAstImpl visitRecordBody(JavaLanguageParser.RecordBodyContext ctx) { 263 final DetailAstImpl objBlock = createImaginary(TokenTypes.OBJBLOCK); 264 processChildren(objBlock, ctx.children); 265 return objBlock; 266 } 267 268 @Override 269 public DetailAstImpl visitCompactConstructorDeclaration( 270 JavaLanguageParser.CompactConstructorDeclarationContext ctx) { 271 final DetailAstImpl compactConstructor = createImaginary(TokenTypes.COMPACT_CTOR_DEF); 272 compactConstructor.addChild(createModifiers(ctx.mods)); 273 compactConstructor.addChild(visit(ctx.id())); 274 compactConstructor.addChild(visit(ctx.constructorBlock())); 275 return compactConstructor; 276 } 277 278 @Override 279 public DetailAstImpl visitClassExtends(JavaLanguageParser.ClassExtendsContext ctx) { 280 final DetailAstImpl classExtends = create(ctx.EXTENDS_CLAUSE()); 281 classExtends.addChild(visit(ctx.type)); 282 return classExtends; 283 } 284 285 @Override 286 public DetailAstImpl visitImplementsClause(JavaLanguageParser.ImplementsClauseContext ctx) { 287 final DetailAstImpl classImplements = create(TokenTypes.IMPLEMENTS_CLAUSE, 288 (Token) ctx.LITERAL_IMPLEMENTS().getPayload()); 289 classImplements.addChild(visit(ctx.typeList())); 290 return classImplements; 291 } 292 293 @Override 294 public DetailAstImpl visitTypeParameters(JavaLanguageParser.TypeParametersContext ctx) { 295 final DetailAstImpl typeParameters = createImaginary(TokenTypes.TYPE_PARAMETERS); 296 typeParameters.addChild(create(TokenTypes.GENERIC_START, (Token) ctx.LT().getPayload())); 297 // Exclude '<' and '>' 298 processChildren(typeParameters, ctx.children.subList(1, ctx.children.size() - 1)); 299 typeParameters.addChild(create(TokenTypes.GENERIC_END, (Token) ctx.GT().getPayload())); 300 return typeParameters; 301 } 302 303 @Override 304 public DetailAstImpl visitTypeParameter(JavaLanguageParser.TypeParameterContext ctx) { 305 final DetailAstImpl typeParameter = createImaginary(TokenTypes.TYPE_PARAMETER); 306 processChildren(typeParameter, ctx.children); 307 return typeParameter; 308 } 309 310 @Override 311 public DetailAstImpl visitTypeUpperBounds(JavaLanguageParser.TypeUpperBoundsContext ctx) { 312 // In this case, we call 'extends` TYPE_UPPER_BOUNDS 313 final DetailAstImpl typeUpperBounds = create(TokenTypes.TYPE_UPPER_BOUNDS, 314 (Token) ctx.EXTENDS_CLAUSE().getPayload()); 315 // 'extends' is child[0] 316 processChildren(typeUpperBounds, ctx.children.subList(1, ctx.children.size())); 317 return typeUpperBounds; 318 } 319 320 @Override 321 public DetailAstImpl visitTypeBound(JavaLanguageParser.TypeBoundContext ctx) { 322 final DetailAstImpl typeBoundType = visit(ctx.typeBoundType(0)); 323 final Iterator<JavaLanguageParser.TypeBoundTypeContext> typeBoundTypeIterator = 324 ctx.typeBoundType().listIterator(1); 325 ctx.BAND().forEach(band -> { 326 addLastSibling(typeBoundType, create(TokenTypes.TYPE_EXTENSION_AND, 327 (Token) band.getPayload())); 328 addLastSibling(typeBoundType, visit(typeBoundTypeIterator.next())); 329 }); 330 return typeBoundType; 331 } 332 333 @Override 334 public DetailAstImpl visitTypeBoundType(JavaLanguageParser.TypeBoundTypeContext ctx) { 335 return flattenedTree(ctx); 336 } 337 338 @Override 339 public DetailAstImpl visitEnumDeclaration(JavaLanguageParser.EnumDeclarationContext ctx) { 340 return createTypeDeclaration(ctx, TokenTypes.ENUM_DEF, ctx.mods); 341 } 342 343 @Override 344 public DetailAstImpl visitEnumBody(JavaLanguageParser.EnumBodyContext ctx) { 345 final DetailAstImpl objBlock = createImaginary(TokenTypes.OBJBLOCK); 346 processChildren(objBlock, ctx.children); 347 return objBlock; 348 } 349 350 @Override 351 public DetailAstImpl visitEnumConstants(JavaLanguageParser.EnumConstantsContext ctx) { 352 return flattenedTree(ctx); 353 } 354 355 @Override 356 public DetailAstImpl visitEnumConstant(JavaLanguageParser.EnumConstantContext ctx) { 357 final DetailAstImpl enumConstant = 358 createImaginary(TokenTypes.ENUM_CONSTANT_DEF); 359 processChildren(enumConstant, ctx.children); 360 return enumConstant; 361 } 362 363 @Override 364 public DetailAstImpl visitEnumBodyDeclarations( 365 JavaLanguageParser.EnumBodyDeclarationsContext ctx) { 366 return flattenedTree(ctx); 367 } 368 369 @Override 370 public DetailAstImpl visitInterfaceDeclaration( 371 JavaLanguageParser.InterfaceDeclarationContext ctx) { 372 return createTypeDeclaration(ctx, TokenTypes.INTERFACE_DEF, ctx.mods); 373 } 374 375 @Override 376 public DetailAstImpl visitInterfaceExtends(JavaLanguageParser.InterfaceExtendsContext ctx) { 377 final DetailAstImpl interfaceExtends = create(ctx.EXTENDS_CLAUSE()); 378 interfaceExtends.addChild(visit(ctx.typeList())); 379 return interfaceExtends; 380 } 381 382 @Override 383 public DetailAstImpl visitClassBody(JavaLanguageParser.ClassBodyContext ctx) { 384 final DetailAstImpl objBlock = createImaginary(TokenTypes.OBJBLOCK); 385 processChildren(objBlock, ctx.children); 386 return objBlock; 387 } 388 389 @Override 390 public DetailAstImpl visitInterfaceBody(JavaLanguageParser.InterfaceBodyContext ctx) { 391 final DetailAstImpl objBlock = createImaginary(TokenTypes.OBJBLOCK); 392 processChildren(objBlock, ctx.children); 393 return objBlock; 394 } 395 396 @Override 397 public DetailAstImpl visitEmptyClass(JavaLanguageParser.EmptyClassContext ctx) { 398 return flattenedTree(ctx); 399 } 400 401 @Override 402 public DetailAstImpl visitClassBlock(JavaLanguageParser.ClassBlockContext ctx) { 403 final DetailAstImpl classBlock; 404 if (ctx.LITERAL_STATIC() == null) { 405 // We call it an INSTANCE_INIT 406 classBlock = createImaginary(TokenTypes.INSTANCE_INIT); 407 } 408 else { 409 classBlock = create(TokenTypes.STATIC_INIT, (Token) ctx.LITERAL_STATIC().getPayload()); 410 classBlock.setText(TokenUtil.getTokenName(TokenTypes.STATIC_INIT)); 411 } 412 classBlock.addChild(visit(ctx.block())); 413 return classBlock; 414 } 415 416 @Override 417 public DetailAstImpl visitMethodDeclaration(JavaLanguageParser.MethodDeclarationContext ctx) { 418 final DetailAstImpl methodDef = createImaginary(TokenTypes.METHOD_DEF); 419 methodDef.addChild(createModifiers(ctx.mods)); 420 421 // Process all children except C style array declarators 422 processChildren(methodDef, ctx.children.stream() 423 .filter(child -> !(child instanceof JavaLanguageParser.ArrayDeclaratorContext)) 424 .collect(Collectors.toUnmodifiableList())); 425 426 // We add C style array declarator brackets to TYPE ast 427 final DetailAstImpl typeAst = (DetailAstImpl) methodDef.findFirstToken(TokenTypes.TYPE); 428 ctx.cStyleArrDec.forEach(child -> typeAst.addChild(visit(child))); 429 430 return methodDef; 431 } 432 433 @Override 434 public DetailAstImpl visitMethodBody(JavaLanguageParser.MethodBodyContext ctx) { 435 return flattenedTree(ctx); 436 } 437 438 @Override 439 public DetailAstImpl visitThrowsList(JavaLanguageParser.ThrowsListContext ctx) { 440 final DetailAstImpl throwsRoot = create(ctx.LITERAL_THROWS()); 441 throwsRoot.addChild(visit(ctx.qualifiedNameList())); 442 return throwsRoot; 443 } 444 445 @Override 446 public DetailAstImpl visitConstructorDeclaration( 447 JavaLanguageParser.ConstructorDeclarationContext ctx) { 448 final DetailAstImpl constructorDeclaration = createImaginary(TokenTypes.CTOR_DEF); 449 constructorDeclaration.addChild(createModifiers(ctx.mods)); 450 processChildren(constructorDeclaration, ctx.children); 451 return constructorDeclaration; 452 } 453 454 @Override 455 public DetailAstImpl visitFieldDeclaration(JavaLanguageParser.FieldDeclarationContext ctx) { 456 final DetailAstImpl dummyNode = new DetailAstImpl(); 457 // Since the TYPE AST is built by visitVariableDeclarator(), we skip it here (child [0]) 458 // We also append the SEMI token to the first child [size() - 1], 459 // until https://github.com/checkstyle/checkstyle/issues/3151 460 processChildren(dummyNode, ctx.children.subList(1, ctx.children.size() - 1)); 461 dummyNode.getFirstChild().addChild(create(ctx.SEMI())); 462 return dummyNode.getFirstChild(); 463 } 464 465 @Override 466 public DetailAstImpl visitInterfaceBodyDeclaration( 467 JavaLanguageParser.InterfaceBodyDeclarationContext ctx) { 468 final DetailAstImpl returnTree; 469 if (ctx.SEMI() == null) { 470 returnTree = visit(ctx.interfaceMemberDeclaration()); 471 } 472 else { 473 returnTree = create(ctx.SEMI()); 474 } 475 return returnTree; 476 } 477 478 @Override 479 public DetailAstImpl visitInterfaceMethodDeclaration( 480 JavaLanguageParser.InterfaceMethodDeclarationContext ctx) { 481 final DetailAstImpl methodDef = createImaginary(TokenTypes.METHOD_DEF); 482 methodDef.addChild(createModifiers(ctx.mods)); 483 484 // Process all children except C style array declarators and modifiers 485 final List<ParseTree> children = ctx.children 486 .stream() 487 .filter(child -> !(child instanceof JavaLanguageParser.ArrayDeclaratorContext)) 488 .collect(Collectors.toUnmodifiableList()); 489 processChildren(methodDef, children); 490 491 // We add C style array declarator brackets to TYPE ast 492 final DetailAstImpl typeAst = (DetailAstImpl) methodDef.findFirstToken(TokenTypes.TYPE); 493 ctx.cStyleArrDec.forEach(child -> typeAst.addChild(visit(child))); 494 495 return methodDef; 496 } 497 498 @Override 499 public DetailAstImpl visitVariableDeclarators( 500 JavaLanguageParser.VariableDeclaratorsContext ctx) { 501 return flattenedTree(ctx); 502 } 503 504 @Override 505 public DetailAstImpl visitVariableDeclarator( 506 JavaLanguageParser.VariableDeclaratorContext ctx) { 507 final DetailAstImpl variableDef = createImaginary(TokenTypes.VARIABLE_DEF); 508 variableDef.addChild(createModifiers(ctx.mods)); 509 510 final DetailAstImpl type = visit(ctx.type); 511 variableDef.addChild(type); 512 variableDef.addChild(visit(ctx.id())); 513 514 // Add C style array declarator brackets to TYPE ast 515 ctx.arrayDeclarator().forEach(child -> type.addChild(visit(child))); 516 517 // If this is an assignment statement, ASSIGN becomes the parent of EXPR 518 final TerminalNode assignNode = ctx.ASSIGN(); 519 if (assignNode != null) { 520 final DetailAstImpl assign = create(assignNode); 521 variableDef.addChild(assign); 522 assign.addChild(visit(ctx.variableInitializer())); 523 } 524 return variableDef; 525 } 526 527 @Override 528 public DetailAstImpl visitVariableDeclaratorId( 529 JavaLanguageParser.VariableDeclaratorIdContext ctx) { 530 final DetailAstImpl root = new DetailAstImpl(); 531 root.addChild(createModifiers(ctx.mods)); 532 final DetailAstImpl type = visit(ctx.type); 533 root.addChild(type); 534 535 final DetailAstImpl declaratorId; 536 if (ctx.LITERAL_THIS() == null) { 537 declaratorId = visit(ctx.qualifiedName()); 538 } 539 else if (ctx.DOT() == null) { 540 declaratorId = create(ctx.LITERAL_THIS()); 541 } 542 else { 543 declaratorId = create(ctx.DOT()); 544 declaratorId.addChild(visit(ctx.qualifiedName())); 545 declaratorId.addChild(create(ctx.LITERAL_THIS())); 546 } 547 548 root.addChild(declaratorId); 549 ctx.arrayDeclarator().forEach(child -> type.addChild(visit(child))); 550 551 return root.getFirstChild(); 552 } 553 554 @Override 555 public DetailAstImpl visitArrayInitializer(JavaLanguageParser.ArrayInitializerContext ctx) { 556 final DetailAstImpl arrayInitializer = create(TokenTypes.ARRAY_INIT, ctx.start); 557 // ARRAY_INIT was child[0] 558 processChildren(arrayInitializer, ctx.children.subList(1, ctx.children.size())); 559 return arrayInitializer; 560 } 561 562 @Override 563 public DetailAstImpl visitClassOrInterfaceType( 564 JavaLanguageParser.ClassOrInterfaceTypeContext ctx) { 565 final DetailAstPair currentAST = new DetailAstPair(); 566 DetailAstPair.addAstChild(currentAST, visit(ctx.id())); 567 DetailAstPair.addAstChild(currentAST, visit(ctx.typeArguments())); 568 569 // This is how we build the annotations/ qualified name/ type parameters tree 570 for (ParserRuleContext extendedContext : ctx.extended) { 571 final DetailAstImpl dot = create(extendedContext.start); 572 DetailAstPair.makeAstRoot(currentAST, dot); 573 extendedContext.children 574 .forEach(child -> DetailAstPair.addAstChild(currentAST, visit(child))); 575 } 576 577 // Create imaginary 'TYPE' parent if specified 578 final DetailAstImpl returnTree; 579 if (ctx.createImaginaryNode) { 580 returnTree = createImaginary(TokenTypes.TYPE); 581 returnTree.addChild(currentAST.root); 582 } 583 else { 584 returnTree = currentAST.root; 585 } 586 return returnTree; 587 } 588 589 @Override 590 public DetailAstImpl visitSimpleTypeArgument( 591 JavaLanguageParser.SimpleTypeArgumentContext ctx) { 592 final DetailAstImpl typeArgument = 593 createImaginary(TokenTypes.TYPE_ARGUMENT); 594 typeArgument.addChild(visit(ctx.typeType())); 595 return typeArgument; 596 } 597 598 @Override 599 public DetailAstImpl visitWildCardTypeArgument( 600 JavaLanguageParser.WildCardTypeArgumentContext ctx) { 601 final DetailAstImpl typeArgument = createImaginary(TokenTypes.TYPE_ARGUMENT); 602 typeArgument.addChild(visit(ctx.annotations())); 603 typeArgument.addChild(create(TokenTypes.WILDCARD_TYPE, 604 (Token) ctx.QUESTION().getPayload())); 605 606 if (ctx.upperBound != null) { 607 final DetailAstImpl upperBound = create(TokenTypes.TYPE_UPPER_BOUNDS, ctx.upperBound); 608 upperBound.addChild(visit(ctx.typeType())); 609 typeArgument.addChild(upperBound); 610 } 611 else if (ctx.lowerBound != null) { 612 final DetailAstImpl lowerBound = create(TokenTypes.TYPE_LOWER_BOUNDS, ctx.lowerBound); 613 lowerBound.addChild(visit(ctx.typeType())); 614 typeArgument.addChild(lowerBound); 615 } 616 617 return typeArgument; 618 } 619 620 @Override 621 public DetailAstImpl visitQualifiedNameList(JavaLanguageParser.QualifiedNameListContext ctx) { 622 return flattenedTree(ctx); 623 } 624 625 @Override 626 public DetailAstImpl visitFormalParameters(JavaLanguageParser.FormalParametersContext ctx) { 627 final DetailAstImpl lparen = create(ctx.LPAREN()); 628 629 // We make a "PARAMETERS" node whether parameters exist or not 630 if (ctx.formalParameterList() == null) { 631 addLastSibling(lparen, createImaginary(TokenTypes.PARAMETERS)); 632 } 633 else { 634 addLastSibling(lparen, visit(ctx.formalParameterList())); 635 } 636 addLastSibling(lparen, create(ctx.RPAREN())); 637 return lparen; 638 } 639 640 @Override 641 public DetailAstImpl visitFormalParameterList( 642 JavaLanguageParser.FormalParameterListContext ctx) { 643 final DetailAstImpl parameters = createImaginary(TokenTypes.PARAMETERS); 644 processChildren(parameters, ctx.children); 645 return parameters; 646 } 647 648 @Override 649 public DetailAstImpl visitFormalParameter(JavaLanguageParser.FormalParameterContext ctx) { 650 final DetailAstImpl variableDeclaratorId = 651 visitVariableDeclaratorId(ctx.variableDeclaratorId()); 652 final DetailAstImpl parameterDef = createImaginary(TokenTypes.PARAMETER_DEF); 653 parameterDef.addChild(variableDeclaratorId); 654 return parameterDef; 655 } 656 657 @Override 658 public DetailAstImpl visitLastFormalParameter( 659 JavaLanguageParser.LastFormalParameterContext ctx) { 660 final DetailAstImpl parameterDef = 661 createImaginary(TokenTypes.PARAMETER_DEF); 662 parameterDef.addChild(visit(ctx.variableDeclaratorId())); 663 final DetailAstImpl ident = (DetailAstImpl) parameterDef.findFirstToken(TokenTypes.IDENT); 664 ident.addPreviousSibling(create(ctx.ELLIPSIS())); 665 // We attach annotations on ellipses in varargs to the 'TYPE' ast 666 final DetailAstImpl type = (DetailAstImpl) parameterDef.findFirstToken(TokenTypes.TYPE); 667 type.addChild(visit(ctx.annotations())); 668 return parameterDef; 669 } 670 671 @Override 672 public DetailAstImpl visitQualifiedName(JavaLanguageParser.QualifiedNameContext ctx) { 673 final DetailAstImpl ast = visit(ctx.id()); 674 final DetailAstPair currentAst = new DetailAstPair(); 675 DetailAstPair.addAstChild(currentAst, ast); 676 677 for (ParserRuleContext extendedContext : ctx.extended) { 678 final DetailAstImpl dot = create(extendedContext.start); 679 DetailAstPair.makeAstRoot(currentAst, dot); 680 final List<ParseTree> childList = extendedContext 681 .children.subList(1, extendedContext.children.size()); 682 processChildren(dot, childList); 683 } 684 return currentAst.getRoot(); 685 } 686 687 @Override 688 public DetailAstImpl visitLiteral(JavaLanguageParser.LiteralContext ctx) { 689 return flattenedTree(ctx); 690 } 691 692 @Override 693 public DetailAstImpl visitIntegerLiteral(JavaLanguageParser.IntegerLiteralContext ctx) { 694 final int[] longTypes = { 695 JavaLanguageLexer.DECIMAL_LITERAL_LONG, 696 JavaLanguageLexer.HEX_LITERAL_LONG, 697 JavaLanguageLexer.OCT_LITERAL_LONG, 698 JavaLanguageLexer.BINARY_LITERAL_LONG, 699 }; 700 701 final int tokenType; 702 if (TokenUtil.isOfType(ctx.start.getType(), longTypes)) { 703 tokenType = TokenTypes.NUM_LONG; 704 } 705 else { 706 tokenType = TokenTypes.NUM_INT; 707 } 708 709 return create(tokenType, ctx.start); 710 } 711 712 @Override 713 public DetailAstImpl visitFloatLiteral(JavaLanguageParser.FloatLiteralContext ctx) { 714 final DetailAstImpl floatLiteral; 715 if (TokenUtil.isOfType(ctx.start.getType(), 716 JavaLanguageLexer.DOUBLE_LITERAL, JavaLanguageLexer.HEX_DOUBLE_LITERAL)) { 717 floatLiteral = create(TokenTypes.NUM_DOUBLE, ctx.start); 718 } 719 else { 720 floatLiteral = create(TokenTypes.NUM_FLOAT, ctx.start); 721 } 722 return floatLiteral; 723 } 724 725 @Override 726 public DetailAstImpl visitTextBlockLiteral(JavaLanguageParser.TextBlockLiteralContext ctx) { 727 final DetailAstImpl textBlockLiteralBegin = create(ctx.TEXT_BLOCK_LITERAL_BEGIN()); 728 textBlockLiteralBegin.addChild(create(ctx.TEXT_BLOCK_CONTENT())); 729 textBlockLiteralBegin.addChild(create(ctx.TEXT_BLOCK_LITERAL_END())); 730 return textBlockLiteralBegin; 731 } 732 733 @Override 734 public DetailAstImpl visitAnnotations(JavaLanguageParser.AnnotationsContext ctx) { 735 final DetailAstImpl annotations; 736 737 if (!ctx.createImaginaryNode && ctx.anno.isEmpty()) { 738 // There are no annotations, and we don't want to create the empty node 739 annotations = null; 740 } 741 else { 742 // There are annotations, or we just want the empty node 743 annotations = createImaginary(TokenTypes.ANNOTATIONS); 744 processChildren(annotations, ctx.anno); 745 } 746 747 return annotations; 748 } 749 750 @Override 751 public DetailAstImpl visitAnnotation(JavaLanguageParser.AnnotationContext ctx) { 752 final DetailAstImpl annotation = createImaginary(TokenTypes.ANNOTATION); 753 processChildren(annotation, ctx.children); 754 return annotation; 755 } 756 757 @Override 758 public DetailAstImpl visitElementValuePairs(JavaLanguageParser.ElementValuePairsContext ctx) { 759 return flattenedTree(ctx); 760 } 761 762 @Override 763 public DetailAstImpl visitElementValuePair(JavaLanguageParser.ElementValuePairContext ctx) { 764 final DetailAstImpl elementValuePair = 765 createImaginary(TokenTypes.ANNOTATION_MEMBER_VALUE_PAIR); 766 processChildren(elementValuePair, ctx.children); 767 return elementValuePair; 768 } 769 770 @Override 771 public DetailAstImpl visitElementValue(JavaLanguageParser.ElementValueContext ctx) { 772 return flattenedTree(ctx); 773 } 774 775 @Override 776 public DetailAstImpl visitElementValueArrayInitializer( 777 JavaLanguageParser.ElementValueArrayInitializerContext ctx) { 778 final DetailAstImpl arrayInit = 779 create(TokenTypes.ANNOTATION_ARRAY_INIT, (Token) ctx.LCURLY().getPayload()); 780 processChildren(arrayInit, ctx.children.subList(1, ctx.children.size())); 781 return arrayInit; 782 } 783 784 @Override 785 public DetailAstImpl visitAnnotationTypeDeclaration( 786 JavaLanguageParser.AnnotationTypeDeclarationContext ctx) { 787 return createTypeDeclaration(ctx, TokenTypes.ANNOTATION_DEF, ctx.mods); 788 } 789 790 @Override 791 public DetailAstImpl visitAnnotationTypeBody( 792 JavaLanguageParser.AnnotationTypeBodyContext ctx) { 793 final DetailAstImpl objBlock = createImaginary(TokenTypes.OBJBLOCK); 794 processChildren(objBlock, ctx.children); 795 return objBlock; 796 } 797 798 @Override 799 public DetailAstImpl visitAnnotationTypeElementDeclaration( 800 JavaLanguageParser.AnnotationTypeElementDeclarationContext ctx) { 801 final DetailAstImpl returnTree; 802 if (ctx.SEMI() == null) { 803 returnTree = visit(ctx.annotationTypeElementRest()); 804 } 805 else { 806 returnTree = create(ctx.SEMI()); 807 } 808 return returnTree; 809 } 810 811 @Override 812 public DetailAstImpl visitAnnotationField(JavaLanguageParser.AnnotationFieldContext ctx) { 813 final DetailAstImpl dummyNode = new DetailAstImpl(); 814 // Since the TYPE AST is built by visitAnnotationMethodOrConstantRest(), we skip it 815 // here (child [0]) 816 processChildren(dummyNode, Collections.singletonList(ctx.children.get(1))); 817 // We also append the SEMI token to the first child [size() - 1], 818 // until https://github.com/checkstyle/checkstyle/issues/3151 819 dummyNode.getFirstChild().addChild(create(ctx.SEMI())); 820 return dummyNode.getFirstChild(); 821 } 822 823 @Override 824 public DetailAstImpl visitAnnotationType(JavaLanguageParser.AnnotationTypeContext ctx) { 825 return flattenedTree(ctx); 826 } 827 828 @Override 829 public DetailAstImpl visitAnnotationMethodRest( 830 JavaLanguageParser.AnnotationMethodRestContext ctx) { 831 final DetailAstImpl annotationFieldDef = 832 createImaginary(TokenTypes.ANNOTATION_FIELD_DEF); 833 annotationFieldDef.addChild(createModifiers(ctx.mods)); 834 annotationFieldDef.addChild(visit(ctx.type)); 835 836 // Process all children except C style array declarators 837 processChildren(annotationFieldDef, ctx.children.stream() 838 .filter(child -> !(child instanceof JavaLanguageParser.ArrayDeclaratorContext)) 839 .collect(Collectors.toUnmodifiableList())); 840 841 // We add C style array declarator brackets to TYPE ast 842 final DetailAstImpl typeAst = 843 (DetailAstImpl) annotationFieldDef.findFirstToken(TokenTypes.TYPE); 844 ctx.cStyleArrDec.forEach(child -> typeAst.addChild(visit(child))); 845 846 return annotationFieldDef; 847 } 848 849 @Override 850 public DetailAstImpl visitDefaultValue(JavaLanguageParser.DefaultValueContext ctx) { 851 final DetailAstImpl defaultValue = create(ctx.LITERAL_DEFAULT()); 852 defaultValue.addChild(visit(ctx.elementValue())); 853 return defaultValue; 854 } 855 856 @Override 857 public DetailAstImpl visitConstructorBlock(JavaLanguageParser.ConstructorBlockContext ctx) { 858 final DetailAstImpl slist = create(TokenTypes.SLIST, ctx.start); 859 // SLIST was child [0] 860 processChildren(slist, ctx.children.subList(1, ctx.children.size())); 861 return slist; 862 } 863 864 @Override 865 public DetailAstImpl visitExplicitCtorCall(JavaLanguageParser.ExplicitCtorCallContext ctx) { 866 final DetailAstImpl root; 867 if (ctx.LITERAL_THIS() == null) { 868 root = create(TokenTypes.SUPER_CTOR_CALL, (Token) ctx.LITERAL_SUPER().getPayload()); 869 } 870 else { 871 root = create(TokenTypes.CTOR_CALL, (Token) ctx.LITERAL_THIS().getPayload()); 872 } 873 root.addChild(visit(ctx.typeArguments())); 874 root.addChild(visit(ctx.arguments())); 875 root.addChild(create(ctx.SEMI())); 876 return root; 877 } 878 879 @Override 880 public DetailAstImpl visitPrimaryCtorCall(JavaLanguageParser.PrimaryCtorCallContext ctx) { 881 final DetailAstImpl primaryCtorCall = create(TokenTypes.SUPER_CTOR_CALL, 882 (Token) ctx.LITERAL_SUPER().getPayload()); 883 // filter 'LITERAL_SUPER' 884 processChildren(primaryCtorCall, ctx.children.stream() 885 .filter(child -> !child.equals(ctx.LITERAL_SUPER())) 886 .collect(Collectors.toUnmodifiableList())); 887 return primaryCtorCall; 888 } 889 890 @Override 891 public DetailAstImpl visitBlock(JavaLanguageParser.BlockContext ctx) { 892 final DetailAstImpl slist = create(TokenTypes.SLIST, ctx.start); 893 // SLIST was child [0] 894 processChildren(slist, ctx.children.subList(1, ctx.children.size())); 895 return slist; 896 } 897 898 @Override 899 public DetailAstImpl visitLocalVar(JavaLanguageParser.LocalVarContext ctx) { 900 return flattenedTree(ctx); 901 } 902 903 @Override 904 public DetailAstImpl visitBlockStat(JavaLanguageParser.BlockStatContext ctx) { 905 return flattenedTree(ctx); 906 } 907 908 @Override 909 public DetailAstImpl visitAssertExp(JavaLanguageParser.AssertExpContext ctx) { 910 final DetailAstImpl assertExp = create(ctx.ASSERT()); 911 // child[0] is 'ASSERT' 912 processChildren(assertExp, ctx.children.subList(1, ctx.children.size())); 913 return assertExp; 914 } 915 916 @Override 917 public DetailAstImpl visitIfStat(JavaLanguageParser.IfStatContext ctx) { 918 final DetailAstImpl ifStat = create(ctx.LITERAL_IF()); 919 // child[0] is 'LITERAL_IF' 920 processChildren(ifStat, ctx.children.subList(1, ctx.children.size())); 921 return ifStat; 922 } 923 924 @Override 925 public DetailAstImpl visitForStat(JavaLanguageParser.ForStatContext ctx) { 926 final DetailAstImpl forInit = create(ctx.start); 927 // child[0] is LITERAL_FOR 928 processChildren(forInit, ctx.children.subList(1, ctx.children.size())); 929 return forInit; 930 } 931 932 @Override 933 public DetailAstImpl visitWhileStat(JavaLanguageParser.WhileStatContext ctx) { 934 final DetailAstImpl whileStatement = create(ctx.start); 935 // 'LITERAL_WHILE' is child[0] 936 processChildren(whileStatement, ctx.children.subList(1, ctx.children.size())); 937 return whileStatement; 938 } 939 940 @Override 941 public DetailAstImpl visitDoStat(JavaLanguageParser.DoStatContext ctx) { 942 final DetailAstImpl doStatement = create(ctx.start); 943 // 'LITERAL_DO' is child[0] 944 doStatement.addChild(visit(ctx.statement())); 945 // We make 'LITERAL_WHILE' into 'DO_WHILE' 946 doStatement.addChild(create(TokenTypes.DO_WHILE, (Token) ctx.LITERAL_WHILE().getPayload())); 947 doStatement.addChild(visit(ctx.parExpression())); 948 doStatement.addChild(create(ctx.SEMI())); 949 return doStatement; 950 } 951 952 @Override 953 public DetailAstImpl visitTryStat(JavaLanguageParser.TryStatContext ctx) { 954 final DetailAstImpl tryStat = create(ctx.start); 955 // child[0] is 'LITERAL_TRY' 956 processChildren(tryStat, ctx.children.subList(1, ctx.children.size())); 957 return tryStat; 958 } 959 960 @Override 961 public DetailAstImpl visitTryWithResourceStat( 962 JavaLanguageParser.TryWithResourceStatContext ctx) { 963 final DetailAstImpl tryWithResources = create(ctx.LITERAL_TRY()); 964 // child[0] is 'LITERAL_TRY' 965 processChildren(tryWithResources, ctx.children.subList(1, ctx.children.size())); 966 return tryWithResources; 967 } 968 969 @Override 970 public DetailAstImpl visitYieldStat(JavaLanguageParser.YieldStatContext ctx) { 971 final DetailAstImpl yieldParent = create(ctx.LITERAL_YIELD()); 972 // LITERAL_YIELD is child[0] 973 processChildren(yieldParent, ctx.children.subList(1, ctx.children.size())); 974 return yieldParent; 975 } 976 977 @Override 978 public DetailAstImpl visitSyncStat(JavaLanguageParser.SyncStatContext ctx) { 979 final DetailAstImpl syncStatement = create(ctx.start); 980 // child[0] is 'LITERAL_SYNCHRONIZED' 981 processChildren(syncStatement, ctx.children.subList(1, ctx.children.size())); 982 return syncStatement; 983 } 984 985 @Override 986 public DetailAstImpl visitReturnStat(JavaLanguageParser.ReturnStatContext ctx) { 987 final DetailAstImpl returnStat = create(ctx.LITERAL_RETURN()); 988 // child[0] is 'LITERAL_RETURN' 989 processChildren(returnStat, ctx.children.subList(1, ctx.children.size())); 990 return returnStat; 991 } 992 993 @Override 994 public DetailAstImpl visitThrowStat(JavaLanguageParser.ThrowStatContext ctx) { 995 final DetailAstImpl throwStat = create(ctx.LITERAL_THROW()); 996 // child[0] is 'LITERAL_THROW' 997 processChildren(throwStat, ctx.children.subList(1, ctx.children.size())); 998 return throwStat; 999 } 1000 1001 @Override 1002 public DetailAstImpl visitBreakStat(JavaLanguageParser.BreakStatContext ctx) { 1003 final DetailAstImpl literalBreak = create(ctx.LITERAL_BREAK()); 1004 // child[0] is 'LITERAL_BREAK' 1005 processChildren(literalBreak, ctx.children.subList(1, ctx.children.size())); 1006 return literalBreak; 1007 } 1008 1009 @Override 1010 public DetailAstImpl visitContinueStat(JavaLanguageParser.ContinueStatContext ctx) { 1011 final DetailAstImpl continueStat = create(ctx.LITERAL_CONTINUE()); 1012 // child[0] is 'LITERAL_CONTINUE' 1013 processChildren(continueStat, ctx.children.subList(1, ctx.children.size())); 1014 return continueStat; 1015 } 1016 1017 @Override 1018 public DetailAstImpl visitEmptyStat(JavaLanguageParser.EmptyStatContext ctx) { 1019 return create(TokenTypes.EMPTY_STAT, ctx.start); 1020 } 1021 1022 @Override 1023 public DetailAstImpl visitExpStat(JavaLanguageParser.ExpStatContext ctx) { 1024 final DetailAstImpl expStatRoot = visit(ctx.statementExpression); 1025 addLastSibling(expStatRoot, create(ctx.SEMI())); 1026 return expStatRoot; 1027 } 1028 1029 @Override 1030 public DetailAstImpl visitLabelStat(JavaLanguageParser.LabelStatContext ctx) { 1031 final DetailAstImpl labelStat = create(TokenTypes.LABELED_STAT, 1032 (Token) ctx.COLON().getPayload()); 1033 labelStat.addChild(visit(ctx.id())); 1034 labelStat.addChild(visit(ctx.statement())); 1035 return labelStat; 1036 } 1037 1038 @Override 1039 public DetailAstImpl visitSwitchExpressionOrStatement( 1040 JavaLanguageParser.SwitchExpressionOrStatementContext ctx) { 1041 final DetailAstImpl switchStat = create(ctx.LITERAL_SWITCH()); 1042 switchStat.addChild(visit(ctx.parExpression())); 1043 switchStat.addChild(create(ctx.LCURLY())); 1044 switchStat.addChild(visit(ctx.switchBlock())); 1045 switchStat.addChild(create(ctx.RCURLY())); 1046 return switchStat; 1047 } 1048 1049 @Override 1050 public DetailAstImpl visitSwitchRules(JavaLanguageParser.SwitchRulesContext ctx) { 1051 final DetailAstImpl dummyRoot = new DetailAstImpl(); 1052 ctx.switchLabeledRule().forEach(switchLabeledRuleContext -> { 1053 final DetailAstImpl switchRule = visit(switchLabeledRuleContext); 1054 final DetailAstImpl switchRuleParent = createImaginary(TokenTypes.SWITCH_RULE); 1055 switchRuleParent.addChild(switchRule); 1056 dummyRoot.addChild(switchRuleParent); 1057 }); 1058 return dummyRoot.getFirstChild(); 1059 } 1060 1061 @Override 1062 public DetailAstImpl visitSwitchBlocks(JavaLanguageParser.SwitchBlocksContext ctx) { 1063 final DetailAstImpl dummyRoot = new DetailAstImpl(); 1064 ctx.groups.forEach(group -> dummyRoot.addChild(visit(group))); 1065 1066 // Add any empty switch labels to end of statement in one 'CASE_GROUP' 1067 if (!ctx.emptyLabels.isEmpty()) { 1068 final DetailAstImpl emptyLabelParent = 1069 createImaginary(TokenTypes.CASE_GROUP); 1070 ctx.emptyLabels.forEach(label -> emptyLabelParent.addChild(visit(label))); 1071 dummyRoot.addChild(emptyLabelParent); 1072 } 1073 return dummyRoot.getFirstChild(); 1074 } 1075 1076 @Override 1077 public DetailAstImpl visitSwitchLabeledExpression( 1078 JavaLanguageParser.SwitchLabeledExpressionContext ctx) { 1079 return flattenedTree(ctx); 1080 } 1081 1082 @Override 1083 public DetailAstImpl visitSwitchLabeledBlock( 1084 JavaLanguageParser.SwitchLabeledBlockContext ctx) { 1085 return flattenedTree(ctx); 1086 } 1087 1088 @Override 1089 public DetailAstImpl visitSwitchLabeledThrow( 1090 JavaLanguageParser.SwitchLabeledThrowContext ctx) { 1091 final DetailAstImpl switchLabel = visit(ctx.switchLabel()); 1092 addLastSibling(switchLabel, create(ctx.LAMBDA())); 1093 final DetailAstImpl literalThrow = create(ctx.LITERAL_THROW()); 1094 literalThrow.addChild(visit(ctx.expression())); 1095 literalThrow.addChild(create(ctx.SEMI())); 1096 addLastSibling(switchLabel, literalThrow); 1097 return switchLabel; 1098 } 1099 1100 @Override 1101 public DetailAstImpl visitElseStat(JavaLanguageParser.ElseStatContext ctx) { 1102 final DetailAstImpl elseStat = create(ctx.LITERAL_ELSE()); 1103 // child[0] is 'LITERAL_ELSE' 1104 processChildren(elseStat, ctx.children.subList(1, ctx.children.size())); 1105 return elseStat; 1106 } 1107 1108 @Override 1109 public DetailAstImpl visitCatchClause(JavaLanguageParser.CatchClauseContext ctx) { 1110 final DetailAstImpl catchClause = create(TokenTypes.LITERAL_CATCH, 1111 (Token) ctx.LITERAL_CATCH().getPayload()); 1112 // 'LITERAL_CATCH' is child[0] 1113 processChildren(catchClause, ctx.children.subList(1, ctx.children.size())); 1114 return catchClause; 1115 } 1116 1117 @Override 1118 public DetailAstImpl visitCatchParameter(JavaLanguageParser.CatchParameterContext ctx) { 1119 final DetailAstImpl catchParameterDef = createImaginary(TokenTypes.PARAMETER_DEF); 1120 catchParameterDef.addChild(createModifiers(ctx.mods)); 1121 // filter mods 1122 processChildren(catchParameterDef, ctx.children.stream() 1123 .filter(child -> !(child instanceof JavaLanguageParser.VariableModifierContext)) 1124 .collect(Collectors.toUnmodifiableList())); 1125 return catchParameterDef; 1126 } 1127 1128 @Override 1129 public DetailAstImpl visitCatchType(JavaLanguageParser.CatchTypeContext ctx) { 1130 final DetailAstImpl type = createImaginary(TokenTypes.TYPE); 1131 processChildren(type, ctx.children); 1132 return type; 1133 } 1134 1135 @Override 1136 public DetailAstImpl visitFinallyBlock(JavaLanguageParser.FinallyBlockContext ctx) { 1137 final DetailAstImpl finallyBlock = create(ctx.LITERAL_FINALLY()); 1138 // child[0] is 'LITERAL_FINALLY' 1139 processChildren(finallyBlock, ctx.children.subList(1, ctx.children.size())); 1140 return finallyBlock; 1141 } 1142 1143 @Override 1144 public DetailAstImpl visitResourceSpecification( 1145 JavaLanguageParser.ResourceSpecificationContext ctx) { 1146 final DetailAstImpl resourceSpecification = 1147 createImaginary(TokenTypes.RESOURCE_SPECIFICATION); 1148 processChildren(resourceSpecification, ctx.children); 1149 return resourceSpecification; 1150 } 1151 1152 @Override 1153 public DetailAstImpl visitResources(JavaLanguageParser.ResourcesContext ctx) { 1154 final DetailAstImpl firstResource = visit(ctx.resource(0)); 1155 final DetailAstImpl resources = createImaginary(TokenTypes.RESOURCES); 1156 resources.addChild(firstResource); 1157 processChildren(resources, ctx.children.subList(1, ctx.children.size())); 1158 return resources; 1159 } 1160 1161 @Override 1162 public DetailAstImpl visitResourceDeclaration( 1163 JavaLanguageParser.ResourceDeclarationContext ctx) { 1164 final DetailAstImpl resource = createImaginary(TokenTypes.RESOURCE); 1165 resource.addChild(visit(ctx.variableDeclaratorId())); 1166 1167 final DetailAstImpl assign = create(ctx.ASSIGN()); 1168 resource.addChild(assign); 1169 assign.addChild(visit(ctx.expression())); 1170 return resource; 1171 } 1172 1173 @Override 1174 public DetailAstImpl visitVariableAccess(JavaLanguageParser.VariableAccessContext ctx) { 1175 final DetailAstImpl resource; 1176 if (ctx.accessList.isEmpty()) { 1177 resource = createImaginary(TokenTypes.RESOURCE); 1178 resource.addChild(visit(ctx.id())); 1179 } 1180 else { 1181 final DetailAstPair currentAst = new DetailAstPair(); 1182 ctx.accessList.forEach(fieldAccess -> { 1183 DetailAstPair.addAstChild(currentAst, visit(fieldAccess.expr())); 1184 DetailAstPair.makeAstRoot(currentAst, create(fieldAccess.DOT())); 1185 }); 1186 resource = createImaginary(TokenTypes.RESOURCE); 1187 resource.addChild(currentAst.root); 1188 if (ctx.LITERAL_THIS() == null) { 1189 resource.getFirstChild().addChild(visit(ctx.id())); 1190 } 1191 else { 1192 resource.getFirstChild().addChild(create(ctx.LITERAL_THIS())); 1193 } 1194 } 1195 return resource; 1196 } 1197 1198 @Override 1199 public DetailAstImpl visitSwitchBlockStatementGroup( 1200 JavaLanguageParser.SwitchBlockStatementGroupContext ctx) { 1201 final DetailAstImpl caseGroup = createImaginary(TokenTypes.CASE_GROUP); 1202 processChildren(caseGroup, ctx.switchLabel()); 1203 final DetailAstImpl sList = createImaginary(TokenTypes.SLIST); 1204 processChildren(sList, ctx.slists); 1205 caseGroup.addChild(sList); 1206 return caseGroup; 1207 } 1208 1209 @Override 1210 public DetailAstImpl visitCaseLabel(JavaLanguageParser.CaseLabelContext ctx) { 1211 final DetailAstImpl caseLabel = create(ctx.LITERAL_CASE()); 1212 // child [0] is 'LITERAL_CASE' 1213 processChildren(caseLabel, ctx.children.subList(1, ctx.children.size())); 1214 return caseLabel; 1215 } 1216 1217 @Override 1218 public DetailAstImpl visitDefaultLabel(JavaLanguageParser.DefaultLabelContext ctx) { 1219 final DetailAstImpl defaultLabel = create(ctx.LITERAL_DEFAULT()); 1220 if (ctx.COLON() != null) { 1221 defaultLabel.addChild(create(ctx.COLON())); 1222 } 1223 return defaultLabel; 1224 } 1225 1226 @Override 1227 public DetailAstImpl visitCaseConstants(JavaLanguageParser.CaseConstantsContext ctx) { 1228 return flattenedTree(ctx); 1229 } 1230 1231 @Override 1232 public DetailAstImpl visitCaseConstant(JavaLanguageParser.CaseConstantContext ctx) { 1233 return flattenedTree(ctx); 1234 } 1235 1236 @Override 1237 public DetailAstImpl visitEnhancedFor(JavaLanguageParser.EnhancedForContext ctx) { 1238 final DetailAstImpl leftParen = create(ctx.LPAREN()); 1239 final DetailAstImpl enhancedForControl = 1240 visit(ctx.getChild(1)); 1241 final DetailAstImpl forEachClause = createImaginary(TokenTypes.FOR_EACH_CLAUSE); 1242 forEachClause.addChild(enhancedForControl); 1243 addLastSibling(leftParen, forEachClause); 1244 addLastSibling(leftParen, create(ctx.RPAREN())); 1245 return leftParen; 1246 } 1247 1248 @Override 1249 public DetailAstImpl visitForFor(JavaLanguageParser.ForForContext ctx) { 1250 final DetailAstImpl dummyRoot = new DetailAstImpl(); 1251 dummyRoot.addChild(create(ctx.LPAREN())); 1252 1253 if (ctx.forInit() == null) { 1254 final DetailAstImpl imaginaryForInitParent = 1255 createImaginary(TokenTypes.FOR_INIT); 1256 dummyRoot.addChild(imaginaryForInitParent); 1257 } 1258 else { 1259 dummyRoot.addChild(visit(ctx.forInit())); 1260 } 1261 1262 dummyRoot.addChild(create(ctx.SEMI(0))); 1263 1264 final DetailAstImpl forCondParent = createImaginary(TokenTypes.FOR_CONDITION); 1265 forCondParent.addChild(visit(ctx.forCond)); 1266 dummyRoot.addChild(forCondParent); 1267 dummyRoot.addChild(create(ctx.SEMI(1))); 1268 1269 final DetailAstImpl forItParent = createImaginary(TokenTypes.FOR_ITERATOR); 1270 forItParent.addChild(visit(ctx.forUpdate)); 1271 dummyRoot.addChild(forItParent); 1272 1273 dummyRoot.addChild(create(ctx.RPAREN())); 1274 1275 return dummyRoot.getFirstChild(); 1276 } 1277 1278 @Override 1279 public DetailAstImpl visitForInit(JavaLanguageParser.ForInitContext ctx) { 1280 final DetailAstImpl forInit = createImaginary(TokenTypes.FOR_INIT); 1281 processChildren(forInit, ctx.children); 1282 return forInit; 1283 } 1284 1285 @Override 1286 public DetailAstImpl visitEnhancedForControl( 1287 JavaLanguageParser.EnhancedForControlContext ctx) { 1288 final DetailAstImpl variableDeclaratorId = 1289 visit(ctx.variableDeclaratorId()); 1290 final DetailAstImpl variableDef = createImaginary(TokenTypes.VARIABLE_DEF); 1291 variableDef.addChild(variableDeclaratorId); 1292 1293 addLastSibling(variableDef, create(ctx.COLON())); 1294 addLastSibling(variableDef, visit(ctx.expression())); 1295 return variableDef; 1296 } 1297 1298 @Override 1299 public DetailAstImpl visitEnhancedForControlWithRecordPattern( 1300 JavaLanguageParser.EnhancedForControlWithRecordPatternContext ctx) { 1301 final DetailAstImpl recordPattern = 1302 visit(ctx.pattern()); 1303 addLastSibling(recordPattern, create(ctx.COLON())); 1304 addLastSibling(recordPattern, visit(ctx.expression())); 1305 return recordPattern; 1306 } 1307 1308 @Override 1309 public DetailAstImpl visitParExpression(JavaLanguageParser.ParExpressionContext ctx) { 1310 return flattenedTree(ctx); 1311 } 1312 1313 @Override 1314 public DetailAstImpl visitExpressionList(JavaLanguageParser.ExpressionListContext ctx) { 1315 final DetailAstImpl elist = createImaginary(TokenTypes.ELIST); 1316 processChildren(elist, ctx.children); 1317 return elist; 1318 } 1319 1320 @Override 1321 public DetailAstImpl visitExpression(JavaLanguageParser.ExpressionContext ctx) { 1322 return buildExpressionNode(ctx.expr()); 1323 } 1324 1325 @Override 1326 public DetailAstImpl visitRefOp(JavaLanguageParser.RefOpContext ctx) { 1327 final DetailAstImpl bop = create(ctx.bop); 1328 final DetailAstImpl leftChild = visit(ctx.expr()); 1329 final DetailAstImpl rightChild = create(TokenTypes.IDENT, ctx.stop); 1330 bop.addChild(leftChild); 1331 bop.addChild(rightChild); 1332 return bop; 1333 } 1334 1335 @Override 1336 public DetailAstImpl visitSuperExp(JavaLanguageParser.SuperExpContext ctx) { 1337 final DetailAstImpl bop = create(ctx.bop); 1338 bop.addChild(visit(ctx.expr())); 1339 bop.addChild(create(ctx.LITERAL_SUPER())); 1340 DetailAstImpl superSuffixParent = visit(ctx.superSuffix()); 1341 1342 if (superSuffixParent == null) { 1343 superSuffixParent = bop; 1344 } 1345 else { 1346 DetailAstImpl firstChild = superSuffixParent; 1347 while (firstChild.getFirstChild() != null) { 1348 firstChild = firstChild.getFirstChild(); 1349 } 1350 firstChild.addPreviousSibling(bop); 1351 } 1352 1353 return superSuffixParent; 1354 } 1355 1356 @Override 1357 public DetailAstImpl visitInstanceOfExp(JavaLanguageParser.InstanceOfExpContext ctx) { 1358 final DetailAstImpl literalInstanceOf = create(ctx.LITERAL_INSTANCEOF()); 1359 literalInstanceOf.addChild(visit(ctx.expr())); 1360 final ParseTree patternOrType = ctx.getChild(2); 1361 1362 final DetailAstImpl patternDef; 1363 if (patternOrType instanceof JavaLanguageParser.ParenPatternContext) { 1364 // Parenthesized pattern has a `PATTERN_DEF` parent 1365 patternDef = createImaginary(TokenTypes.PATTERN_DEF); 1366 patternDef.addChild(visit(patternOrType)); 1367 } 1368 else { 1369 patternDef = visit(patternOrType); 1370 } 1371 literalInstanceOf.addChild(patternDef); 1372 return literalInstanceOf; 1373 } 1374 1375 @Override 1376 public DetailAstImpl visitBitShift(JavaLanguageParser.BitShiftContext ctx) { 1377 final DetailAstImpl shiftOperation; 1378 1379 // We determine the type of shift operation in the parser, instead of the 1380 // lexer as in older grammars. This makes it easier to parse type parameters 1381 // and less than/ greater than operators in general. 1382 if (ctx.LT().size() == LEFT_SHIFT.length()) { 1383 shiftOperation = create(TokenTypes.SL, (Token) ctx.LT(0).getPayload()); 1384 shiftOperation.setText(LEFT_SHIFT); 1385 } 1386 else if (ctx.GT().size() == UNSIGNED_RIGHT_SHIFT.length()) { 1387 shiftOperation = create(TokenTypes.BSR, (Token) ctx.GT(0).getPayload()); 1388 shiftOperation.setText(UNSIGNED_RIGHT_SHIFT); 1389 } 1390 else { 1391 shiftOperation = create(TokenTypes.SR, (Token) ctx.GT(0).getPayload()); 1392 shiftOperation.setText(RIGHT_SHIFT); 1393 } 1394 1395 shiftOperation.addChild(visit(ctx.expr(0))); 1396 shiftOperation.addChild(visit(ctx.expr(1))); 1397 return shiftOperation; 1398 } 1399 1400 @Override 1401 public DetailAstImpl visitNewExp(JavaLanguageParser.NewExpContext ctx) { 1402 final DetailAstImpl newExp = create(ctx.LITERAL_NEW()); 1403 // child [0] is LITERAL_NEW 1404 processChildren(newExp, ctx.children.subList(1, ctx.children.size())); 1405 return newExp; 1406 } 1407 1408 @Override 1409 public DetailAstImpl visitPrefix(JavaLanguageParser.PrefixContext ctx) { 1410 final int tokenType; 1411 switch (ctx.prefix.getType()) { 1412 case JavaLanguageLexer.PLUS: 1413 tokenType = TokenTypes.UNARY_PLUS; 1414 break; 1415 case JavaLanguageLexer.MINUS: 1416 tokenType = TokenTypes.UNARY_MINUS; 1417 break; 1418 default: 1419 tokenType = ctx.prefix.getType(); 1420 } 1421 final DetailAstImpl prefix = create(tokenType, ctx.prefix); 1422 prefix.addChild(visit(ctx.expr())); 1423 return prefix; 1424 } 1425 1426 @Override 1427 public DetailAstImpl visitCastExp(JavaLanguageParser.CastExpContext ctx) { 1428 final DetailAstImpl cast = create(TokenTypes.TYPECAST, (Token) ctx.LPAREN().getPayload()); 1429 // child [0] is LPAREN 1430 processChildren(cast, ctx.children.subList(1, ctx.children.size())); 1431 return cast; 1432 } 1433 1434 @Override 1435 public DetailAstImpl visitIndexOp(JavaLanguageParser.IndexOpContext ctx) { 1436 // LBRACK -> INDEX_OP is root of this AST 1437 final DetailAstImpl indexOp = create(TokenTypes.INDEX_OP, 1438 (Token) ctx.LBRACK().getPayload()); 1439 1440 // add expression(IDENT) on LHS 1441 indexOp.addChild(visit(ctx.expr(0))); 1442 1443 // create imaginary node for expression on RHS 1444 final DetailAstImpl expr = visit(ctx.expr(1)); 1445 final DetailAstImpl imaginaryExpr = createImaginary(TokenTypes.EXPR); 1446 imaginaryExpr.addChild(expr); 1447 indexOp.addChild(imaginaryExpr); 1448 1449 // complete AST by adding RBRACK 1450 indexOp.addChild(create(ctx.RBRACK())); 1451 return indexOp; 1452 } 1453 1454 @Override 1455 public DetailAstImpl visitInvOp(JavaLanguageParser.InvOpContext ctx) { 1456 final DetailAstPair currentAst = new DetailAstPair(); 1457 1458 final DetailAstImpl returnAst = visit(ctx.expr()); 1459 DetailAstPair.addAstChild(currentAst, returnAst); 1460 DetailAstPair.makeAstRoot(currentAst, create(ctx.bop)); 1461 1462 DetailAstPair.addAstChild(currentAst, 1463 visit(ctx.nonWildcardTypeArguments())); 1464 DetailAstPair.addAstChild(currentAst, visit(ctx.id())); 1465 final DetailAstImpl lparen = create(TokenTypes.METHOD_CALL, 1466 (Token) ctx.LPAREN().getPayload()); 1467 DetailAstPair.makeAstRoot(currentAst, lparen); 1468 1469 // We always add an 'ELIST' node 1470 final DetailAstImpl expressionList = Optional.ofNullable(visit(ctx.expressionList())) 1471 .orElseGet(() -> createImaginary(TokenTypes.ELIST)); 1472 1473 DetailAstPair.addAstChild(currentAst, expressionList); 1474 DetailAstPair.addAstChild(currentAst, create(ctx.RPAREN())); 1475 1476 return currentAst.root; 1477 } 1478 1479 @Override 1480 public DetailAstImpl visitInitExp(JavaLanguageParser.InitExpContext ctx) { 1481 final DetailAstImpl dot = create(ctx.bop); 1482 dot.addChild(visit(ctx.expr())); 1483 final DetailAstImpl literalNew = create(ctx.LITERAL_NEW()); 1484 literalNew.addChild(visit(ctx.nonWildcardTypeArguments())); 1485 literalNew.addChild(visit(ctx.innerCreator())); 1486 dot.addChild(literalNew); 1487 return dot; 1488 } 1489 1490 @Override 1491 public DetailAstImpl visitSimpleMethodCall(JavaLanguageParser.SimpleMethodCallContext ctx) { 1492 final DetailAstImpl methodCall = create(TokenTypes.METHOD_CALL, 1493 (Token) ctx.LPAREN().getPayload()); 1494 methodCall.addChild(visit(ctx.id())); 1495 // We always add an 'ELIST' node 1496 final DetailAstImpl expressionList = Optional.ofNullable(visit(ctx.expressionList())) 1497 .orElseGet(() -> createImaginary(TokenTypes.ELIST)); 1498 1499 methodCall.addChild(expressionList); 1500 methodCall.addChild(create((Token) ctx.RPAREN().getPayload())); 1501 return methodCall; 1502 } 1503 1504 @Override 1505 public DetailAstImpl visitLambdaExp(JavaLanguageParser.LambdaExpContext ctx) { 1506 final DetailAstImpl lambda = create(ctx.LAMBDA()); 1507 lambda.addChild(visit(ctx.lambdaParameters())); 1508 1509 final JavaLanguageParser.BlockContext blockContext = ctx.block(); 1510 final DetailAstImpl rightHandLambdaChild; 1511 if (blockContext != null) { 1512 rightHandLambdaChild = visit(blockContext); 1513 } 1514 else { 1515 // Lambda expression child is built the same way that we build 1516 // the initial expression node in visitExpression, i.e. with 1517 // an imaginary EXPR node. This results in nested EXPR nodes 1518 // in the AST. 1519 rightHandLambdaChild = buildExpressionNode(ctx.expr()); 1520 } 1521 lambda.addChild(rightHandLambdaChild); 1522 return lambda; 1523 } 1524 1525 @Override 1526 public DetailAstImpl visitThisExp(JavaLanguageParser.ThisExpContext ctx) { 1527 final DetailAstImpl bop = create(ctx.bop); 1528 bop.addChild(visit(ctx.expr())); 1529 bop.addChild(create(ctx.LITERAL_THIS())); 1530 return bop; 1531 } 1532 1533 @Override 1534 public DetailAstImpl visitPrimaryExp(JavaLanguageParser.PrimaryExpContext ctx) { 1535 return flattenedTree(ctx); 1536 } 1537 1538 @Override 1539 public DetailAstImpl visitPostfix(JavaLanguageParser.PostfixContext ctx) { 1540 final DetailAstImpl postfix; 1541 if (ctx.postfix.getType() == JavaLanguageLexer.INC) { 1542 postfix = create(TokenTypes.POST_INC, ctx.postfix); 1543 } 1544 else { 1545 postfix = create(TokenTypes.POST_DEC, ctx.postfix); 1546 } 1547 postfix.addChild(visit(ctx.expr())); 1548 return postfix; 1549 } 1550 1551 @Override 1552 public DetailAstImpl visitMethodRef(JavaLanguageParser.MethodRefContext ctx) { 1553 final DetailAstImpl doubleColon = create(TokenTypes.METHOD_REF, 1554 (Token) ctx.DOUBLE_COLON().getPayload()); 1555 final List<ParseTree> children = ctx.children.stream() 1556 .filter(child -> !child.equals(ctx.DOUBLE_COLON())) 1557 .collect(Collectors.toUnmodifiableList()); 1558 processChildren(doubleColon, children); 1559 return doubleColon; 1560 } 1561 1562 @Override 1563 public DetailAstImpl visitTernaryOp(JavaLanguageParser.TernaryOpContext ctx) { 1564 final DetailAstImpl root = create(ctx.QUESTION()); 1565 processChildren(root, ctx.children.stream() 1566 .filter(child -> !child.equals(ctx.QUESTION())) 1567 .collect(Collectors.toUnmodifiableList())); 1568 return root; 1569 } 1570 1571 @Override 1572 public DetailAstImpl visitBinOp(JavaLanguageParser.BinOpContext ctx) { 1573 final DetailAstImpl bop = create(ctx.bop); 1574 1575 // To improve performance, we iterate through binary operations 1576 // since they are frequently deeply nested. 1577 final List<JavaLanguageParser.BinOpContext> binOpList = new ArrayList<>(); 1578 ParseTree firstExpression = ctx.expr(0); 1579 while (firstExpression instanceof JavaLanguageParser.BinOpContext) { 1580 // Get all nested binOps 1581 binOpList.add((JavaLanguageParser.BinOpContext) firstExpression); 1582 firstExpression = ((JavaLanguageParser.BinOpContext) firstExpression).expr(0); 1583 } 1584 1585 if (binOpList.isEmpty()) { 1586 final DetailAstImpl leftChild = visit(ctx.children.get(0)); 1587 bop.addChild(leftChild); 1588 } 1589 else { 1590 // Map all descendants to individual AST's since we can parallelize this 1591 // operation 1592 final Queue<DetailAstImpl> descendantList = binOpList.parallelStream() 1593 .map(this::getInnerBopAst) 1594 .collect(Collectors.toCollection(ConcurrentLinkedQueue::new)); 1595 1596 bop.addChild(descendantList.poll()); 1597 DetailAstImpl pointer = bop.getFirstChild(); 1598 // Build tree 1599 for (DetailAstImpl descendant : descendantList) { 1600 pointer.getFirstChild().addPreviousSibling(descendant); 1601 pointer = descendant; 1602 } 1603 } 1604 1605 bop.addChild(visit(ctx.children.get(2))); 1606 return bop; 1607 } 1608 1609 /** 1610 * Builds the binary operation (binOp) AST. 1611 * 1612 * @param descendant the BinOpContext to build AST from 1613 * @return binOp AST 1614 */ 1615 private DetailAstImpl getInnerBopAst(JavaLanguageParser.BinOpContext descendant) { 1616 final DetailAstImpl innerBop = create(descendant.bop); 1617 final JavaLanguageParser.ExprContext expr = descendant.expr(0); 1618 if (!(expr instanceof JavaLanguageParser.BinOpContext)) { 1619 innerBop.addChild(visit(expr)); 1620 } 1621 innerBop.addChild(visit(descendant.expr(1))); 1622 return innerBop; 1623 } 1624 1625 @Override 1626 public DetailAstImpl visitMethodCall(JavaLanguageParser.MethodCallContext ctx) { 1627 final DetailAstImpl methodCall = create(TokenTypes.METHOD_CALL, 1628 (Token) ctx.LPAREN().getPayload()); 1629 // We always add an 'ELIST' node 1630 final DetailAstImpl expressionList = Optional.ofNullable(visit(ctx.expressionList())) 1631 .orElseGet(() -> createImaginary(TokenTypes.ELIST)); 1632 1633 final DetailAstImpl dot = create(ctx.DOT()); 1634 dot.addChild(visit(ctx.expr())); 1635 dot.addChild(visit(ctx.id())); 1636 methodCall.addChild(dot); 1637 methodCall.addChild(expressionList); 1638 methodCall.addChild(create((Token) ctx.RPAREN().getPayload())); 1639 return methodCall; 1640 } 1641 1642 @Override 1643 public DetailAstImpl visitTypeCastParameters( 1644 JavaLanguageParser.TypeCastParametersContext ctx) { 1645 final DetailAstImpl typeType = visit(ctx.typeType(0)); 1646 for (int i = 0; i < ctx.BAND().size(); i++) { 1647 addLastSibling(typeType, create(TokenTypes.TYPE_EXTENSION_AND, 1648 (Token) ctx.BAND(i).getPayload())); 1649 addLastSibling(typeType, visit(ctx.typeType(i + 1))); 1650 } 1651 return typeType; 1652 } 1653 1654 @Override 1655 public DetailAstImpl visitSingleLambdaParam(JavaLanguageParser.SingleLambdaParamContext ctx) { 1656 return flattenedTree(ctx); 1657 } 1658 1659 @Override 1660 public DetailAstImpl visitFormalLambdaParam(JavaLanguageParser.FormalLambdaParamContext ctx) { 1661 final DetailAstImpl lparen = create(ctx.LPAREN()); 1662 1663 // We add an 'PARAMETERS' node here whether it exists or not 1664 final DetailAstImpl parameters = Optional.ofNullable(visit(ctx.formalParameterList())) 1665 .orElseGet(() -> createImaginary(TokenTypes.PARAMETERS)); 1666 addLastSibling(lparen, parameters); 1667 addLastSibling(lparen, create(ctx.RPAREN())); 1668 return lparen; 1669 } 1670 1671 @Override 1672 public DetailAstImpl visitMultiLambdaParam(JavaLanguageParser.MultiLambdaParamContext ctx) { 1673 final DetailAstImpl lparen = create(ctx.LPAREN()); 1674 addLastSibling(lparen, visit(ctx.multiLambdaParams())); 1675 addLastSibling(lparen, create(ctx.RPAREN())); 1676 return lparen; 1677 } 1678 1679 @Override 1680 public DetailAstImpl visitMultiLambdaParams(JavaLanguageParser.MultiLambdaParamsContext ctx) { 1681 final DetailAstImpl parameters = createImaginary(TokenTypes.PARAMETERS); 1682 parameters.addChild(createLambdaParameter(ctx.id(0))); 1683 1684 for (int i = 0; i < ctx.COMMA().size(); i++) { 1685 parameters.addChild(create(ctx.COMMA(i))); 1686 parameters.addChild(createLambdaParameter(ctx.id(i + 1))); 1687 } 1688 return parameters; 1689 } 1690 1691 /** 1692 * Creates a 'PARAMETER_DEF' node for a lambda expression, with 1693 * imaginary modifier and type nodes. 1694 * 1695 * @param ctx the IdContext to create imaginary nodes for 1696 * @return DetailAstImpl of lambda parameter 1697 */ 1698 private DetailAstImpl createLambdaParameter(JavaLanguageParser.IdContext ctx) { 1699 final DetailAstImpl ident = visitId(ctx); 1700 final DetailAstImpl parameter = createImaginary(TokenTypes.PARAMETER_DEF); 1701 final DetailAstImpl modifiers = createImaginary(TokenTypes.MODIFIERS); 1702 final DetailAstImpl type = createImaginary(TokenTypes.TYPE); 1703 parameter.addChild(modifiers); 1704 parameter.addChild(type); 1705 parameter.addChild(ident); 1706 return parameter; 1707 } 1708 1709 @Override 1710 public DetailAstImpl visitParenPrimary(JavaLanguageParser.ParenPrimaryContext ctx) { 1711 return flattenedTree(ctx); 1712 } 1713 1714 @Override 1715 public DetailAstImpl visitTokenPrimary(JavaLanguageParser.TokenPrimaryContext ctx) { 1716 return flattenedTree(ctx); 1717 } 1718 1719 @Override 1720 public DetailAstImpl visitClassRefPrimary(JavaLanguageParser.ClassRefPrimaryContext ctx) { 1721 final DetailAstImpl dot = create(ctx.DOT()); 1722 final DetailAstImpl primaryTypeNoArray = visit(ctx.type); 1723 dot.addChild(primaryTypeNoArray); 1724 if (TokenUtil.isOfType(primaryTypeNoArray, TokenTypes.DOT)) { 1725 // We append '[]' to the qualified name 'TYPE' `ast 1726 ctx.arrayDeclarator() 1727 .forEach(child -> primaryTypeNoArray.addChild(visit(child))); 1728 } 1729 else { 1730 ctx.arrayDeclarator() 1731 .forEach(child -> addLastSibling(primaryTypeNoArray, visit(child))); 1732 } 1733 dot.addChild(create(ctx.LITERAL_CLASS())); 1734 return dot; 1735 } 1736 1737 @Override 1738 public DetailAstImpl visitPrimitivePrimary(JavaLanguageParser.PrimitivePrimaryContext ctx) { 1739 final DetailAstImpl dot = create(ctx.DOT()); 1740 final DetailAstImpl primaryTypeNoArray = visit(ctx.type); 1741 dot.addChild(primaryTypeNoArray); 1742 ctx.arrayDeclarator().forEach(child -> dot.addChild(visit(child))); 1743 dot.addChild(create(ctx.LITERAL_CLASS())); 1744 return dot; 1745 } 1746 1747 @Override 1748 public DetailAstImpl visitCreator(JavaLanguageParser.CreatorContext ctx) { 1749 return flattenedTree(ctx); 1750 } 1751 1752 @Override 1753 public DetailAstImpl visitCreatedNameObject(JavaLanguageParser.CreatedNameObjectContext ctx) { 1754 final DetailAstPair currentAST = new DetailAstPair(); 1755 DetailAstPair.addAstChild(currentAST, visit(ctx.annotations())); 1756 DetailAstPair.addAstChild(currentAST, visit(ctx.id())); 1757 DetailAstPair.addAstChild(currentAST, visit(ctx.typeArgumentsOrDiamond())); 1758 1759 // This is how we build the type arguments/ qualified name tree 1760 for (ParserRuleContext extendedContext : ctx.extended) { 1761 final DetailAstImpl dot = create(extendedContext.start); 1762 DetailAstPair.makeAstRoot(currentAST, dot); 1763 final List<ParseTree> childList = extendedContext 1764 .children.subList(1, extendedContext.children.size()); 1765 processChildren(dot, childList); 1766 } 1767 1768 return currentAST.root; 1769 } 1770 1771 @Override 1772 public DetailAstImpl visitCreatedNamePrimitive( 1773 JavaLanguageParser.CreatedNamePrimitiveContext ctx) { 1774 return flattenedTree(ctx); 1775 } 1776 1777 @Override 1778 public DetailAstImpl visitInnerCreator(JavaLanguageParser.InnerCreatorContext ctx) { 1779 return flattenedTree(ctx); 1780 } 1781 1782 @Override 1783 public DetailAstImpl visitArrayCreatorRest(JavaLanguageParser.ArrayCreatorRestContext ctx) { 1784 final DetailAstImpl arrayDeclarator = create(TokenTypes.ARRAY_DECLARATOR, 1785 (Token) ctx.LBRACK().getPayload()); 1786 final JavaLanguageParser.ExpressionContext expression = ctx.expression(); 1787 final TerminalNode rbrack = ctx.RBRACK(); 1788 // child[0] is LBRACK 1789 for (int i = 1; i < ctx.children.size(); i++) { 1790 if (ctx.children.get(i) == rbrack) { 1791 arrayDeclarator.addChild(create(rbrack)); 1792 } 1793 else if (ctx.children.get(i) == expression) { 1794 // Handle '[8]', etc. 1795 arrayDeclarator.addChild(visit(expression)); 1796 } 1797 else { 1798 addLastSibling(arrayDeclarator, visit(ctx.children.get(i))); 1799 } 1800 } 1801 return arrayDeclarator; 1802 } 1803 1804 @Override 1805 public DetailAstImpl visitBracketsWithExp(JavaLanguageParser.BracketsWithExpContext ctx) { 1806 final DetailAstImpl dummyRoot = new DetailAstImpl(); 1807 dummyRoot.addChild(visit(ctx.annotations())); 1808 final DetailAstImpl arrayDeclarator = 1809 create(TokenTypes.ARRAY_DECLARATOR, (Token) ctx.LBRACK().getPayload()); 1810 arrayDeclarator.addChild(visit(ctx.expression())); 1811 arrayDeclarator.addChild(create(ctx.stop)); 1812 dummyRoot.addChild(arrayDeclarator); 1813 return dummyRoot.getFirstChild(); 1814 } 1815 1816 @Override 1817 public DetailAstImpl visitClassCreatorRest(JavaLanguageParser.ClassCreatorRestContext ctx) { 1818 return flattenedTree(ctx); 1819 } 1820 1821 @Override 1822 public DetailAstImpl visitDiamond(JavaLanguageParser.DiamondContext ctx) { 1823 final DetailAstImpl typeArguments = 1824 createImaginary(TokenTypes.TYPE_ARGUMENTS); 1825 typeArguments.addChild(create(TokenTypes.GENERIC_START, 1826 (Token) ctx.LT().getPayload())); 1827 typeArguments.addChild(create(TokenTypes.GENERIC_END, 1828 (Token) ctx.GT().getPayload())); 1829 return typeArguments; 1830 } 1831 1832 @Override 1833 public DetailAstImpl visitTypeArgs(JavaLanguageParser.TypeArgsContext ctx) { 1834 return flattenedTree(ctx); 1835 } 1836 1837 @Override 1838 public DetailAstImpl visitNonWildcardDiamond( 1839 JavaLanguageParser.NonWildcardDiamondContext ctx) { 1840 final DetailAstImpl typeArguments = 1841 createImaginary(TokenTypes.TYPE_ARGUMENTS); 1842 typeArguments.addChild(create(TokenTypes.GENERIC_START, 1843 (Token) ctx.LT().getPayload())); 1844 typeArguments.addChild(create(TokenTypes.GENERIC_END, 1845 (Token) ctx.GT().getPayload())); 1846 return typeArguments; 1847 } 1848 1849 @Override 1850 public DetailAstImpl visitNonWildcardTypeArguments( 1851 JavaLanguageParser.NonWildcardTypeArgumentsContext ctx) { 1852 final DetailAstImpl typeArguments = createImaginary(TokenTypes.TYPE_ARGUMENTS); 1853 typeArguments.addChild(create(TokenTypes.GENERIC_START, (Token) ctx.LT().getPayload())); 1854 typeArguments.addChild(visit(ctx.typeArgumentsTypeList())); 1855 typeArguments.addChild(create(TokenTypes.GENERIC_END, (Token) ctx.GT().getPayload())); 1856 return typeArguments; 1857 } 1858 1859 @Override 1860 public DetailAstImpl visitTypeArgumentsTypeList( 1861 JavaLanguageParser.TypeArgumentsTypeListContext ctx) { 1862 final DetailAstImpl firstIdent = visit(ctx.typeType(0)); 1863 final DetailAstImpl firstTypeArgument = createImaginary(TokenTypes.TYPE_ARGUMENT); 1864 firstTypeArgument.addChild(firstIdent); 1865 1866 for (int i = 0; i < ctx.COMMA().size(); i++) { 1867 addLastSibling(firstTypeArgument, create(ctx.COMMA(i))); 1868 final DetailAstImpl ident = visit(ctx.typeType(i + 1)); 1869 final DetailAstImpl typeArgument = createImaginary(TokenTypes.TYPE_ARGUMENT); 1870 typeArgument.addChild(ident); 1871 addLastSibling(firstTypeArgument, typeArgument); 1872 } 1873 return firstTypeArgument; 1874 } 1875 1876 @Override 1877 public DetailAstImpl visitTypeList(JavaLanguageParser.TypeListContext ctx) { 1878 return flattenedTree(ctx); 1879 } 1880 1881 @Override 1882 public DetailAstImpl visitTypeType(JavaLanguageParser.TypeTypeContext ctx) { 1883 final DetailAstImpl type = createImaginary(TokenTypes.TYPE); 1884 processChildren(type, ctx.children); 1885 1886 final DetailAstImpl returnTree; 1887 if (ctx.createImaginaryNode) { 1888 returnTree = type; 1889 } 1890 else { 1891 returnTree = type.getFirstChild(); 1892 } 1893 return returnTree; 1894 } 1895 1896 @Override 1897 public DetailAstImpl visitArrayDeclarator(JavaLanguageParser.ArrayDeclaratorContext ctx) { 1898 final DetailAstImpl arrayDeclarator = create(TokenTypes.ARRAY_DECLARATOR, 1899 (Token) ctx.LBRACK().getPayload()); 1900 arrayDeclarator.addChild(create(ctx.RBRACK())); 1901 1902 final DetailAstImpl returnTree; 1903 final DetailAstImpl annotations = visit(ctx.anno); 1904 if (annotations == null) { 1905 returnTree = arrayDeclarator; 1906 } 1907 else { 1908 returnTree = annotations; 1909 addLastSibling(returnTree, arrayDeclarator); 1910 } 1911 return returnTree; 1912 } 1913 1914 @Override 1915 public DetailAstImpl visitPrimitiveType(JavaLanguageParser.PrimitiveTypeContext ctx) { 1916 return create(ctx.start); 1917 } 1918 1919 @Override 1920 public DetailAstImpl visitTypeArguments(JavaLanguageParser.TypeArgumentsContext ctx) { 1921 final DetailAstImpl typeArguments = createImaginary(TokenTypes.TYPE_ARGUMENTS); 1922 typeArguments.addChild(create(TokenTypes.GENERIC_START, (Token) ctx.LT().getPayload())); 1923 // Exclude '<' and '>' 1924 processChildren(typeArguments, ctx.children.subList(1, ctx.children.size() - 1)); 1925 typeArguments.addChild(create(TokenTypes.GENERIC_END, (Token) ctx.GT().getPayload())); 1926 return typeArguments; 1927 } 1928 1929 @Override 1930 public DetailAstImpl visitSuperSuffixDot(JavaLanguageParser.SuperSuffixDotContext ctx) { 1931 final DetailAstImpl root; 1932 if (ctx.LPAREN() == null) { 1933 root = create(ctx.DOT()); 1934 root.addChild(visit(ctx.id())); 1935 } 1936 else { 1937 root = create(TokenTypes.METHOD_CALL, (Token) ctx.LPAREN().getPayload()); 1938 1939 final DetailAstImpl dot = create(ctx.DOT()); 1940 dot.addChild(visit(ctx.id())); 1941 root.addChild(dot); 1942 1943 final DetailAstImpl expressionList = Optional.ofNullable(visit(ctx.expressionList())) 1944 .orElseGet(() -> createImaginary(TokenTypes.ELIST)); 1945 root.addChild(expressionList); 1946 1947 root.addChild(create(ctx.RPAREN())); 1948 } 1949 1950 return root; 1951 } 1952 1953 @Override 1954 public DetailAstImpl visitArguments(JavaLanguageParser.ArgumentsContext ctx) { 1955 final DetailAstImpl lparen = create(ctx.LPAREN()); 1956 1957 // We always add an 'ELIST' node 1958 final DetailAstImpl expressionList = Optional.ofNullable(visit(ctx.expressionList())) 1959 .orElseGet(() -> createImaginary(TokenTypes.ELIST)); 1960 addLastSibling(lparen, expressionList); 1961 addLastSibling(lparen, create(ctx.RPAREN())); 1962 return lparen; 1963 } 1964 1965 @Override 1966 public DetailAstImpl visitPattern(JavaLanguageParser.PatternContext ctx) { 1967 final JavaLanguageParser.InnerPatternContext innerPattern = ctx.innerPattern(); 1968 final ParserRuleContext primaryPattern = innerPattern.primaryPattern(); 1969 final ParserRuleContext recordPattern = innerPattern.recordPattern(); 1970 final boolean isSimpleTypePattern = primaryPattern != null 1971 && primaryPattern.getChild(0) instanceof JavaLanguageParser.TypePatternContext; 1972 1973 final DetailAstImpl pattern; 1974 1975 if (recordPattern != null) { 1976 pattern = visit(recordPattern); 1977 } 1978 else if (isSimpleTypePattern) { 1979 // For simple type pattern like 'Integer i`, we do not add `PATTERN_DEF` parent 1980 pattern = visit(primaryPattern); 1981 } 1982 else { 1983 pattern = createImaginary(TokenTypes.PATTERN_DEF); 1984 pattern.addChild(visit(ctx.getChild(0))); 1985 } 1986 return pattern; 1987 } 1988 1989 @Override 1990 public DetailAstImpl visitInnerPattern(JavaLanguageParser.InnerPatternContext ctx) { 1991 return flattenedTree(ctx); 1992 } 1993 1994 @Override 1995 public DetailAstImpl visitGuardedPattern(JavaLanguageParser.GuardedPatternContext ctx) { 1996 final DetailAstImpl guardAstNode = flattenedTree(ctx.guard()); 1997 guardAstNode.addChild(visit(ctx.primaryPattern())); 1998 guardAstNode.addChild(visit(ctx.expression())); 1999 return guardAstNode; 2000 } 2001 2002 @Override 2003 public DetailAstImpl visitParenPattern(JavaLanguageParser.ParenPatternContext ctx) { 2004 final DetailAstImpl lparen = create(ctx.LPAREN()); 2005 final ParseTree innerPattern = ctx.getChild(1); 2006 lparen.addChild(visit(innerPattern)); 2007 lparen.addChild(create(ctx.RPAREN())); 2008 return lparen; 2009 } 2010 2011 @Override 2012 public DetailAstImpl visitRecordPatternDef(JavaLanguageParser.RecordPatternDefContext ctx) { 2013 return flattenedTree(ctx); 2014 } 2015 2016 @Override 2017 public DetailAstImpl visitTypePatternDef( 2018 JavaLanguageParser.TypePatternDefContext ctx) { 2019 final DetailAstImpl type = visit(ctx.type); 2020 final DetailAstImpl patternVariableDef = createImaginary(TokenTypes.PATTERN_VARIABLE_DEF); 2021 patternVariableDef.addChild(createModifiers(ctx.mods)); 2022 patternVariableDef.addChild(type); 2023 patternVariableDef.addChild(visit(ctx.id())); 2024 return patternVariableDef; 2025 } 2026 2027 @Override 2028 public DetailAstImpl visitUnnamedPatternDef(JavaLanguageParser.UnnamedPatternDefContext ctx) { 2029 return create(TokenTypes.UNNAMED_PATTERN_DEF, ctx.start); 2030 } 2031 2032 @Override 2033 public DetailAstImpl visitRecordPattern(JavaLanguageParser.RecordPatternContext ctx) { 2034 final DetailAstImpl recordPattern = createImaginary(TokenTypes.RECORD_PATTERN_DEF); 2035 recordPattern.addChild(createModifiers(ctx.mods)); 2036 processChildren(recordPattern, 2037 ctx.children.subList(ctx.mods.size(), ctx.children.size())); 2038 return recordPattern; 2039 } 2040 2041 @Override 2042 public DetailAstImpl visitRecordComponentPatternList( 2043 JavaLanguageParser.RecordComponentPatternListContext ctx) { 2044 final DetailAstImpl recordComponents = 2045 createImaginary(TokenTypes.RECORD_PATTERN_COMPONENTS); 2046 processChildren(recordComponents, ctx.children); 2047 return recordComponents; 2048 } 2049 2050 @Override 2051 public DetailAstImpl visitPermittedSubclassesAndInterfaces( 2052 JavaLanguageParser.PermittedSubclassesAndInterfacesContext ctx) { 2053 final DetailAstImpl literalPermits = 2054 create(TokenTypes.PERMITS_CLAUSE, (Token) ctx.LITERAL_PERMITS().getPayload()); 2055 // 'LITERAL_PERMITS' is child[0] 2056 processChildren(literalPermits, ctx.children.subList(1, ctx.children.size())); 2057 return literalPermits; 2058 } 2059 2060 @Override 2061 public DetailAstImpl visitId(JavaLanguageParser.IdContext ctx) { 2062 return create(TokenTypes.IDENT, ctx.start); 2063 } 2064 2065 /** 2066 * Builds the AST for a particular node, then returns a "flattened" tree 2067 * of siblings. This method should be used in rule contexts such as 2068 * {@code variableDeclarators}, where we have both terminals and non-terminals. 2069 * 2070 * @param ctx the ParserRuleContext to base tree on 2071 * @return flattened DetailAstImpl 2072 */ 2073 private DetailAstImpl flattenedTree(ParserRuleContext ctx) { 2074 final DetailAstImpl dummyNode = new DetailAstImpl(); 2075 processChildren(dummyNode, ctx.children); 2076 return dummyNode.getFirstChild(); 2077 } 2078 2079 /** 2080 * Adds all the children from the given ParseTree or JavaParserContext 2081 * list to the parent DetailAstImpl. 2082 * 2083 * @param parent the DetailAstImpl to add children to 2084 * @param children the list of children to add 2085 */ 2086 private void processChildren(DetailAstImpl parent, List<? extends ParseTree> children) { 2087 children.forEach(child -> { 2088 if (child instanceof TerminalNode) { 2089 // Child is a token, create a new DetailAstImpl and add it to parent 2090 parent.addChild(create((TerminalNode) child)); 2091 } 2092 else { 2093 // Child is another rule context; visit it, create token, and add to parent 2094 parent.addChild(visit(child)); 2095 } 2096 }); 2097 } 2098 2099 /** 2100 * Create a DetailAstImpl from a given token and token type. This method 2101 * should be used for imaginary nodes only, i.e. 'OBJBLOCK -> OBJBLOCK', 2102 * where the text on the RHS matches the text on the LHS. 2103 * 2104 * @param tokenType the token type of this DetailAstImpl 2105 * @return new DetailAstImpl of given type 2106 */ 2107 private static DetailAstImpl createImaginary(int tokenType) { 2108 final DetailAstImpl detailAst = new DetailAstImpl(); 2109 detailAst.setType(tokenType); 2110 detailAst.setText(TokenUtil.getTokenName(tokenType)); 2111 return detailAst; 2112 } 2113 2114 /** 2115 * Create a DetailAstImpl from a given token and token type. This method 2116 * should be used for literal nodes only, i.e. 'PACKAGE_DEF -> package'. 2117 * 2118 * @param tokenType the token type of this DetailAstImpl 2119 * @param startToken the first token that appears in this DetailAstImpl. 2120 * @return new DetailAstImpl of given type 2121 */ 2122 private DetailAstImpl create(int tokenType, Token startToken) { 2123 final DetailAstImpl ast = create(startToken); 2124 ast.setType(tokenType); 2125 return ast; 2126 } 2127 2128 /** 2129 * Create a DetailAstImpl from a given token. This method should be 2130 * used for terminal nodes, i.e. {@code LCURLY}, when we are building 2131 * an AST for a specific token, regardless of position. 2132 * 2133 * @param token the token to build the DetailAstImpl from 2134 * @return new DetailAstImpl of given type 2135 */ 2136 private DetailAstImpl create(Token token) { 2137 final int tokenIndex = token.getTokenIndex(); 2138 final List<Token> tokensToLeft = 2139 tokens.getHiddenTokensToLeft(tokenIndex, JavaLanguageLexer.COMMENTS); 2140 final List<Token> tokensToRight = 2141 tokens.getHiddenTokensToRight(tokenIndex, JavaLanguageLexer.COMMENTS); 2142 2143 final DetailAstImpl detailAst = new DetailAstImpl(); 2144 detailAst.initialize(token); 2145 if (tokensToLeft != null) { 2146 detailAst.setHiddenBefore(tokensToLeft); 2147 } 2148 if (tokensToRight != null) { 2149 detailAst.setHiddenAfter(tokensToRight); 2150 } 2151 return detailAst; 2152 } 2153 2154 /** 2155 * Create a DetailAstImpl from a given TerminalNode. This method should be 2156 * used for terminal nodes, i.e. {@code @}. 2157 * 2158 * @param node the TerminalNode to build the DetailAstImpl from 2159 * @return new DetailAstImpl of given type 2160 */ 2161 private DetailAstImpl create(TerminalNode node) { 2162 return create((Token) node.getPayload()); 2163 } 2164 2165 /** 2166 * Creates a type declaration DetailAstImpl from a given rule context. 2167 * 2168 * @param ctx ParserRuleContext we are in 2169 * @param type the type declaration to create 2170 * @param modifierList respective modifiers 2171 * @return type declaration DetailAstImpl 2172 */ 2173 private DetailAstImpl createTypeDeclaration(ParserRuleContext ctx, int type, 2174 List<? extends ParseTree> modifierList) { 2175 final DetailAstImpl typeDeclaration = createImaginary(type); 2176 typeDeclaration.addChild(createModifiers(modifierList)); 2177 processChildren(typeDeclaration, ctx.children); 2178 return typeDeclaration; 2179 } 2180 2181 /** 2182 * Builds the modifiers AST. 2183 * 2184 * @param modifierList the list of modifier contexts 2185 * @return "MODIFIERS" ast 2186 */ 2187 private DetailAstImpl createModifiers(List<? extends ParseTree> modifierList) { 2188 final DetailAstImpl mods = createImaginary(TokenTypes.MODIFIERS); 2189 processChildren(mods, modifierList); 2190 return mods; 2191 } 2192 2193 /** 2194 * Add new sibling to the end of existing siblings. 2195 * 2196 * @param self DetailAstImpl to add last sibling to 2197 * @param sibling DetailAstImpl sibling to add 2198 */ 2199 private static void addLastSibling(DetailAstImpl self, DetailAstImpl sibling) { 2200 DetailAstImpl nextSibling = self; 2201 if (nextSibling != null) { 2202 while (nextSibling.getNextSibling() != null) { 2203 nextSibling = nextSibling.getNextSibling(); 2204 } 2205 nextSibling.setNextSibling(sibling); 2206 } 2207 } 2208 2209 @Override 2210 public DetailAstImpl visit(ParseTree tree) { 2211 DetailAstImpl ast = null; 2212 if (tree != null) { 2213 ast = tree.accept(this); 2214 } 2215 return ast; 2216 } 2217 2218 /** 2219 * Builds an expression node. This is used to build the root of an expression with 2220 * an imaginary {@code EXPR} node. 2221 * 2222 * @param exprNode expression to build node for 2223 * @return expression DetailAstImpl node 2224 */ 2225 private DetailAstImpl buildExpressionNode(ParseTree exprNode) { 2226 final DetailAstImpl expression = visit(exprNode); 2227 2228 final DetailAstImpl exprRoot; 2229 if (TokenUtil.isOfType(expression, EXPRESSIONS_WITH_NO_EXPR_ROOT)) { 2230 exprRoot = expression; 2231 } 2232 else { 2233 // create imaginary 'EXPR' node as root of expression 2234 exprRoot = createImaginary(TokenTypes.EXPR); 2235 exprRoot.addChild(expression); 2236 } 2237 return exprRoot; 2238 } 2239 2240 /** 2241 * Used to swap and organize DetailAstImpl subtrees. 2242 */ 2243 private static final class DetailAstPair { 2244 2245 /** The root DetailAstImpl of this pair. */ 2246 private DetailAstImpl root; 2247 2248 /** The child (potentially with siblings) of this pair. */ 2249 private DetailAstImpl child; 2250 2251 /** 2252 * Moves child reference to the last child. 2253 */ 2254 private void advanceChildToEnd() { 2255 while (child.getNextSibling() != null) { 2256 child = child.getNextSibling(); 2257 } 2258 } 2259 2260 /** 2261 * Returns the root node. 2262 * 2263 * @return the root node 2264 */ 2265 private DetailAstImpl getRoot() { 2266 return root; 2267 } 2268 2269 /** 2270 * This method is used to replace the {@code ^} (set as root node) ANTLR2 2271 * operator. 2272 * 2273 * @param pair the DetailAstPair to use for swapping nodes 2274 * @param ast the new root 2275 */ 2276 private static void makeAstRoot(DetailAstPair pair, DetailAstImpl ast) { 2277 ast.addChild(pair.root); 2278 pair.child = pair.root; 2279 pair.advanceChildToEnd(); 2280 pair.root = ast; 2281 } 2282 2283 /** 2284 * Adds a child (or new root) to the given DetailAstPair. 2285 * 2286 * @param pair the DetailAstPair to add child to 2287 * @param ast the child to add 2288 */ 2289 private static void addAstChild(DetailAstPair pair, DetailAstImpl ast) { 2290 if (ast != null) { 2291 if (pair.root == null) { 2292 pair.root = ast; 2293 } 2294 else { 2295 pair.child.setNextSibling(ast); 2296 } 2297 pair.child = ast; 2298 } 2299 } 2300 } 2301}