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 = createImaginary(TokenTypes.RESOURCE); 1176 1177 final DetailAstImpl childNode; 1178 if (ctx.LITERAL_THIS() == null) { 1179 childNode = visit(ctx.id()); 1180 } 1181 else { 1182 childNode = create(ctx.LITERAL_THIS()); 1183 } 1184 1185 if (ctx.accessList.isEmpty()) { 1186 resource.addChild(childNode); 1187 } 1188 else { 1189 final DetailAstPair currentAst = new DetailAstPair(); 1190 ctx.accessList.forEach(fieldAccess -> { 1191 DetailAstPair.addAstChild(currentAst, visit(fieldAccess.expr())); 1192 DetailAstPair.makeAstRoot(currentAst, create(fieldAccess.DOT())); 1193 }); 1194 resource.addChild(currentAst.getRoot()); 1195 resource.getFirstChild().addChild(childNode); 1196 } 1197 return resource; 1198 } 1199 1200 @Override 1201 public DetailAstImpl visitSwitchBlockStatementGroup( 1202 JavaLanguageParser.SwitchBlockStatementGroupContext ctx) { 1203 final DetailAstImpl caseGroup = createImaginary(TokenTypes.CASE_GROUP); 1204 processChildren(caseGroup, ctx.switchLabel()); 1205 final DetailAstImpl sList = createImaginary(TokenTypes.SLIST); 1206 processChildren(sList, ctx.slists); 1207 caseGroup.addChild(sList); 1208 return caseGroup; 1209 } 1210 1211 @Override 1212 public DetailAstImpl visitCaseLabel(JavaLanguageParser.CaseLabelContext ctx) { 1213 final DetailAstImpl caseLabel = create(ctx.LITERAL_CASE()); 1214 // child [0] is 'LITERAL_CASE' 1215 processChildren(caseLabel, ctx.children.subList(1, ctx.children.size())); 1216 return caseLabel; 1217 } 1218 1219 @Override 1220 public DetailAstImpl visitDefaultLabel(JavaLanguageParser.DefaultLabelContext ctx) { 1221 final DetailAstImpl defaultLabel = create(ctx.LITERAL_DEFAULT()); 1222 if (ctx.COLON() != null) { 1223 defaultLabel.addChild(create(ctx.COLON())); 1224 } 1225 return defaultLabel; 1226 } 1227 1228 @Override 1229 public DetailAstImpl visitCaseConstants(JavaLanguageParser.CaseConstantsContext ctx) { 1230 return flattenedTree(ctx); 1231 } 1232 1233 @Override 1234 public DetailAstImpl visitCaseConstant(JavaLanguageParser.CaseConstantContext ctx) { 1235 return flattenedTree(ctx); 1236 } 1237 1238 @Override 1239 public DetailAstImpl visitEnhancedFor(JavaLanguageParser.EnhancedForContext ctx) { 1240 final DetailAstImpl leftParen = create(ctx.LPAREN()); 1241 final DetailAstImpl enhancedForControl = 1242 visit(ctx.getChild(1)); 1243 final DetailAstImpl forEachClause = createImaginary(TokenTypes.FOR_EACH_CLAUSE); 1244 forEachClause.addChild(enhancedForControl); 1245 addLastSibling(leftParen, forEachClause); 1246 addLastSibling(leftParen, create(ctx.RPAREN())); 1247 return leftParen; 1248 } 1249 1250 @Override 1251 public DetailAstImpl visitForFor(JavaLanguageParser.ForForContext ctx) { 1252 final DetailAstImpl dummyRoot = new DetailAstImpl(); 1253 dummyRoot.addChild(create(ctx.LPAREN())); 1254 1255 if (ctx.forInit() == null) { 1256 final DetailAstImpl imaginaryForInitParent = 1257 createImaginary(TokenTypes.FOR_INIT); 1258 dummyRoot.addChild(imaginaryForInitParent); 1259 } 1260 else { 1261 dummyRoot.addChild(visit(ctx.forInit())); 1262 } 1263 1264 dummyRoot.addChild(create(ctx.SEMI(0))); 1265 1266 final DetailAstImpl forCondParent = createImaginary(TokenTypes.FOR_CONDITION); 1267 forCondParent.addChild(visit(ctx.forCond)); 1268 dummyRoot.addChild(forCondParent); 1269 dummyRoot.addChild(create(ctx.SEMI(1))); 1270 1271 final DetailAstImpl forItParent = createImaginary(TokenTypes.FOR_ITERATOR); 1272 forItParent.addChild(visit(ctx.forUpdate)); 1273 dummyRoot.addChild(forItParent); 1274 1275 dummyRoot.addChild(create(ctx.RPAREN())); 1276 1277 return dummyRoot.getFirstChild(); 1278 } 1279 1280 @Override 1281 public DetailAstImpl visitForInit(JavaLanguageParser.ForInitContext ctx) { 1282 final DetailAstImpl forInit = createImaginary(TokenTypes.FOR_INIT); 1283 processChildren(forInit, ctx.children); 1284 return forInit; 1285 } 1286 1287 @Override 1288 public DetailAstImpl visitEnhancedForControl( 1289 JavaLanguageParser.EnhancedForControlContext ctx) { 1290 final DetailAstImpl variableDeclaratorId = 1291 visit(ctx.variableDeclaratorId()); 1292 final DetailAstImpl variableDef = createImaginary(TokenTypes.VARIABLE_DEF); 1293 variableDef.addChild(variableDeclaratorId); 1294 1295 addLastSibling(variableDef, create(ctx.COLON())); 1296 addLastSibling(variableDef, visit(ctx.expression())); 1297 return variableDef; 1298 } 1299 1300 @Override 1301 public DetailAstImpl visitEnhancedForControlWithRecordPattern( 1302 JavaLanguageParser.EnhancedForControlWithRecordPatternContext ctx) { 1303 final DetailAstImpl recordPattern = 1304 visit(ctx.pattern()); 1305 addLastSibling(recordPattern, create(ctx.COLON())); 1306 addLastSibling(recordPattern, visit(ctx.expression())); 1307 return recordPattern; 1308 } 1309 1310 @Override 1311 public DetailAstImpl visitParExpression(JavaLanguageParser.ParExpressionContext ctx) { 1312 return flattenedTree(ctx); 1313 } 1314 1315 @Override 1316 public DetailAstImpl visitExpressionList(JavaLanguageParser.ExpressionListContext ctx) { 1317 final DetailAstImpl elist = createImaginary(TokenTypes.ELIST); 1318 processChildren(elist, ctx.children); 1319 return elist; 1320 } 1321 1322 @Override 1323 public DetailAstImpl visitExpression(JavaLanguageParser.ExpressionContext ctx) { 1324 return buildExpressionNode(ctx.expr()); 1325 } 1326 1327 @Override 1328 public DetailAstImpl visitRefOp(JavaLanguageParser.RefOpContext ctx) { 1329 final DetailAstImpl bop = create(ctx.bop); 1330 final DetailAstImpl leftChild = visit(ctx.expr()); 1331 final DetailAstImpl rightChild = create(TokenTypes.IDENT, ctx.stop); 1332 bop.addChild(leftChild); 1333 bop.addChild(rightChild); 1334 return bop; 1335 } 1336 1337 @Override 1338 public DetailAstImpl visitSuperExp(JavaLanguageParser.SuperExpContext ctx) { 1339 final DetailAstImpl bop = create(ctx.bop); 1340 bop.addChild(visit(ctx.expr())); 1341 bop.addChild(create(ctx.LITERAL_SUPER())); 1342 DetailAstImpl superSuffixParent = visit(ctx.superSuffix()); 1343 1344 if (superSuffixParent == null) { 1345 superSuffixParent = bop; 1346 } 1347 else { 1348 DetailAstImpl firstChild = superSuffixParent; 1349 while (firstChild.getFirstChild() != null) { 1350 firstChild = firstChild.getFirstChild(); 1351 } 1352 firstChild.addPreviousSibling(bop); 1353 } 1354 1355 return superSuffixParent; 1356 } 1357 1358 @Override 1359 public DetailAstImpl visitInstanceOfExp(JavaLanguageParser.InstanceOfExpContext ctx) { 1360 final DetailAstImpl literalInstanceOf = create(ctx.LITERAL_INSTANCEOF()); 1361 literalInstanceOf.addChild(visit(ctx.expr())); 1362 final ParseTree patternOrType = ctx.getChild(2); 1363 1364 final DetailAstImpl patternDef; 1365 if (patternOrType instanceof JavaLanguageParser.ParenPatternContext) { 1366 // Parenthesized pattern has a `PATTERN_DEF` parent 1367 patternDef = createImaginary(TokenTypes.PATTERN_DEF); 1368 patternDef.addChild(visit(patternOrType)); 1369 } 1370 else { 1371 patternDef = visit(patternOrType); 1372 } 1373 literalInstanceOf.addChild(patternDef); 1374 return literalInstanceOf; 1375 } 1376 1377 @Override 1378 public DetailAstImpl visitBitShift(JavaLanguageParser.BitShiftContext ctx) { 1379 final DetailAstImpl shiftOperation; 1380 1381 // We determine the type of shift operation in the parser, instead of the 1382 // lexer as in older grammars. This makes it easier to parse type parameters 1383 // and less than/ greater than operators in general. 1384 if (ctx.LT().size() == LEFT_SHIFT.length()) { 1385 shiftOperation = create(TokenTypes.SL, (Token) ctx.LT(0).getPayload()); 1386 shiftOperation.setText(LEFT_SHIFT); 1387 } 1388 else if (ctx.GT().size() == UNSIGNED_RIGHT_SHIFT.length()) { 1389 shiftOperation = create(TokenTypes.BSR, (Token) ctx.GT(0).getPayload()); 1390 shiftOperation.setText(UNSIGNED_RIGHT_SHIFT); 1391 } 1392 else { 1393 shiftOperation = create(TokenTypes.SR, (Token) ctx.GT(0).getPayload()); 1394 shiftOperation.setText(RIGHT_SHIFT); 1395 } 1396 1397 shiftOperation.addChild(visit(ctx.expr(0))); 1398 shiftOperation.addChild(visit(ctx.expr(1))); 1399 return shiftOperation; 1400 } 1401 1402 @Override 1403 public DetailAstImpl visitNewExp(JavaLanguageParser.NewExpContext ctx) { 1404 final DetailAstImpl newExp = create(ctx.LITERAL_NEW()); 1405 // child [0] is LITERAL_NEW 1406 processChildren(newExp, ctx.children.subList(1, ctx.children.size())); 1407 return newExp; 1408 } 1409 1410 @Override 1411 public DetailAstImpl visitPrefix(JavaLanguageParser.PrefixContext ctx) { 1412 final int tokenType; 1413 switch (ctx.prefix.getType()) { 1414 case JavaLanguageLexer.PLUS: 1415 tokenType = TokenTypes.UNARY_PLUS; 1416 break; 1417 case JavaLanguageLexer.MINUS: 1418 tokenType = TokenTypes.UNARY_MINUS; 1419 break; 1420 default: 1421 tokenType = ctx.prefix.getType(); 1422 } 1423 final DetailAstImpl prefix = create(tokenType, ctx.prefix); 1424 prefix.addChild(visit(ctx.expr())); 1425 return prefix; 1426 } 1427 1428 @Override 1429 public DetailAstImpl visitCastExp(JavaLanguageParser.CastExpContext ctx) { 1430 final DetailAstImpl cast = create(TokenTypes.TYPECAST, (Token) ctx.LPAREN().getPayload()); 1431 // child [0] is LPAREN 1432 processChildren(cast, ctx.children.subList(1, ctx.children.size())); 1433 return cast; 1434 } 1435 1436 @Override 1437 public DetailAstImpl visitIndexOp(JavaLanguageParser.IndexOpContext ctx) { 1438 // LBRACK -> INDEX_OP is root of this AST 1439 final DetailAstImpl indexOp = create(TokenTypes.INDEX_OP, 1440 (Token) ctx.LBRACK().getPayload()); 1441 1442 // add expression(IDENT) on LHS 1443 indexOp.addChild(visit(ctx.expr(0))); 1444 1445 // create imaginary node for expression on RHS 1446 final DetailAstImpl expr = visit(ctx.expr(1)); 1447 final DetailAstImpl imaginaryExpr = createImaginary(TokenTypes.EXPR); 1448 imaginaryExpr.addChild(expr); 1449 indexOp.addChild(imaginaryExpr); 1450 1451 // complete AST by adding RBRACK 1452 indexOp.addChild(create(ctx.RBRACK())); 1453 return indexOp; 1454 } 1455 1456 @Override 1457 public DetailAstImpl visitInvOp(JavaLanguageParser.InvOpContext ctx) { 1458 final DetailAstPair currentAst = new DetailAstPair(); 1459 1460 final DetailAstImpl returnAst = visit(ctx.expr()); 1461 DetailAstPair.addAstChild(currentAst, returnAst); 1462 DetailAstPair.makeAstRoot(currentAst, create(ctx.bop)); 1463 1464 DetailAstPair.addAstChild(currentAst, 1465 visit(ctx.nonWildcardTypeArguments())); 1466 DetailAstPair.addAstChild(currentAst, visit(ctx.id())); 1467 final DetailAstImpl lparen = create(TokenTypes.METHOD_CALL, 1468 (Token) ctx.LPAREN().getPayload()); 1469 DetailAstPair.makeAstRoot(currentAst, lparen); 1470 1471 // We always add an 'ELIST' node 1472 final DetailAstImpl expressionList = Optional.ofNullable(visit(ctx.expressionList())) 1473 .orElseGet(() -> createImaginary(TokenTypes.ELIST)); 1474 1475 DetailAstPair.addAstChild(currentAst, expressionList); 1476 DetailAstPair.addAstChild(currentAst, create(ctx.RPAREN())); 1477 1478 return currentAst.root; 1479 } 1480 1481 @Override 1482 public DetailAstImpl visitInitExp(JavaLanguageParser.InitExpContext ctx) { 1483 final DetailAstImpl dot = create(ctx.bop); 1484 dot.addChild(visit(ctx.expr())); 1485 final DetailAstImpl literalNew = create(ctx.LITERAL_NEW()); 1486 literalNew.addChild(visit(ctx.nonWildcardTypeArguments())); 1487 literalNew.addChild(visit(ctx.innerCreator())); 1488 dot.addChild(literalNew); 1489 return dot; 1490 } 1491 1492 @Override 1493 public DetailAstImpl visitSimpleMethodCall(JavaLanguageParser.SimpleMethodCallContext ctx) { 1494 final DetailAstImpl methodCall = create(TokenTypes.METHOD_CALL, 1495 (Token) ctx.LPAREN().getPayload()); 1496 methodCall.addChild(visit(ctx.id())); 1497 // We always add an 'ELIST' node 1498 final DetailAstImpl expressionList = Optional.ofNullable(visit(ctx.expressionList())) 1499 .orElseGet(() -> createImaginary(TokenTypes.ELIST)); 1500 1501 methodCall.addChild(expressionList); 1502 methodCall.addChild(create((Token) ctx.RPAREN().getPayload())); 1503 return methodCall; 1504 } 1505 1506 @Override 1507 public DetailAstImpl visitLambdaExp(JavaLanguageParser.LambdaExpContext ctx) { 1508 final DetailAstImpl lambda = create(ctx.LAMBDA()); 1509 lambda.addChild(visit(ctx.lambdaParameters())); 1510 1511 final JavaLanguageParser.BlockContext blockContext = ctx.block(); 1512 final DetailAstImpl rightHandLambdaChild; 1513 if (blockContext != null) { 1514 rightHandLambdaChild = visit(blockContext); 1515 } 1516 else { 1517 // Lambda expression child is built the same way that we build 1518 // the initial expression node in visitExpression, i.e. with 1519 // an imaginary EXPR node. This results in nested EXPR nodes 1520 // in the AST. 1521 rightHandLambdaChild = buildExpressionNode(ctx.expr()); 1522 } 1523 lambda.addChild(rightHandLambdaChild); 1524 return lambda; 1525 } 1526 1527 @Override 1528 public DetailAstImpl visitThisExp(JavaLanguageParser.ThisExpContext ctx) { 1529 final DetailAstImpl bop = create(ctx.bop); 1530 bop.addChild(visit(ctx.expr())); 1531 bop.addChild(create(ctx.LITERAL_THIS())); 1532 return bop; 1533 } 1534 1535 @Override 1536 public DetailAstImpl visitPrimaryExp(JavaLanguageParser.PrimaryExpContext ctx) { 1537 return flattenedTree(ctx); 1538 } 1539 1540 @Override 1541 public DetailAstImpl visitPostfix(JavaLanguageParser.PostfixContext ctx) { 1542 final DetailAstImpl postfix; 1543 if (ctx.postfix.getType() == JavaLanguageLexer.INC) { 1544 postfix = create(TokenTypes.POST_INC, ctx.postfix); 1545 } 1546 else { 1547 postfix = create(TokenTypes.POST_DEC, ctx.postfix); 1548 } 1549 postfix.addChild(visit(ctx.expr())); 1550 return postfix; 1551 } 1552 1553 @Override 1554 public DetailAstImpl visitMethodRef(JavaLanguageParser.MethodRefContext ctx) { 1555 final DetailAstImpl doubleColon = create(TokenTypes.METHOD_REF, 1556 (Token) ctx.DOUBLE_COLON().getPayload()); 1557 final List<ParseTree> children = ctx.children.stream() 1558 .filter(child -> !child.equals(ctx.DOUBLE_COLON())) 1559 .collect(Collectors.toUnmodifiableList()); 1560 processChildren(doubleColon, children); 1561 return doubleColon; 1562 } 1563 1564 @Override 1565 public DetailAstImpl visitTernaryOp(JavaLanguageParser.TernaryOpContext ctx) { 1566 final DetailAstImpl root = create(ctx.QUESTION()); 1567 processChildren(root, ctx.children.stream() 1568 .filter(child -> !child.equals(ctx.QUESTION())) 1569 .collect(Collectors.toUnmodifiableList())); 1570 return root; 1571 } 1572 1573 @Override 1574 public DetailAstImpl visitBinOp(JavaLanguageParser.BinOpContext ctx) { 1575 final DetailAstImpl bop = create(ctx.bop); 1576 1577 // To improve performance, we iterate through binary operations 1578 // since they are frequently deeply nested. 1579 final List<JavaLanguageParser.BinOpContext> binOpList = new ArrayList<>(); 1580 ParseTree firstExpression = ctx.expr(0); 1581 while (firstExpression instanceof JavaLanguageParser.BinOpContext) { 1582 // Get all nested binOps 1583 binOpList.add((JavaLanguageParser.BinOpContext) firstExpression); 1584 firstExpression = ((JavaLanguageParser.BinOpContext) firstExpression).expr(0); 1585 } 1586 1587 if (binOpList.isEmpty()) { 1588 final DetailAstImpl leftChild = visit(ctx.children.get(0)); 1589 bop.addChild(leftChild); 1590 } 1591 else { 1592 // Map all descendants to individual AST's since we can parallelize this 1593 // operation 1594 final Queue<DetailAstImpl> descendantList = binOpList.parallelStream() 1595 .map(this::getInnerBopAst) 1596 .collect(Collectors.toCollection(ConcurrentLinkedQueue::new)); 1597 1598 bop.addChild(descendantList.poll()); 1599 DetailAstImpl pointer = bop.getFirstChild(); 1600 // Build tree 1601 for (DetailAstImpl descendant : descendantList) { 1602 pointer.getFirstChild().addPreviousSibling(descendant); 1603 pointer = descendant; 1604 } 1605 } 1606 1607 bop.addChild(visit(ctx.children.get(2))); 1608 return bop; 1609 } 1610 1611 /** 1612 * Builds the binary operation (binOp) AST. 1613 * 1614 * @param descendant the BinOpContext to build AST from 1615 * @return binOp AST 1616 */ 1617 private DetailAstImpl getInnerBopAst(JavaLanguageParser.BinOpContext descendant) { 1618 final DetailAstImpl innerBop = create(descendant.bop); 1619 final JavaLanguageParser.ExprContext expr = descendant.expr(0); 1620 if (!(expr instanceof JavaLanguageParser.BinOpContext)) { 1621 innerBop.addChild(visit(expr)); 1622 } 1623 innerBop.addChild(visit(descendant.expr(1))); 1624 return innerBop; 1625 } 1626 1627 @Override 1628 public DetailAstImpl visitMethodCall(JavaLanguageParser.MethodCallContext ctx) { 1629 final DetailAstImpl methodCall = create(TokenTypes.METHOD_CALL, 1630 (Token) ctx.LPAREN().getPayload()); 1631 // We always add an 'ELIST' node 1632 final DetailAstImpl expressionList = Optional.ofNullable(visit(ctx.expressionList())) 1633 .orElseGet(() -> createImaginary(TokenTypes.ELIST)); 1634 1635 final DetailAstImpl dot = create(ctx.DOT()); 1636 dot.addChild(visit(ctx.expr())); 1637 dot.addChild(visit(ctx.id())); 1638 methodCall.addChild(dot); 1639 methodCall.addChild(expressionList); 1640 methodCall.addChild(create((Token) ctx.RPAREN().getPayload())); 1641 return methodCall; 1642 } 1643 1644 @Override 1645 public DetailAstImpl visitTypeCastParameters( 1646 JavaLanguageParser.TypeCastParametersContext ctx) { 1647 final DetailAstImpl typeType = visit(ctx.typeType(0)); 1648 for (int i = 0; i < ctx.BAND().size(); i++) { 1649 addLastSibling(typeType, create(TokenTypes.TYPE_EXTENSION_AND, 1650 (Token) ctx.BAND(i).getPayload())); 1651 addLastSibling(typeType, visit(ctx.typeType(i + 1))); 1652 } 1653 return typeType; 1654 } 1655 1656 @Override 1657 public DetailAstImpl visitSingleLambdaParam(JavaLanguageParser.SingleLambdaParamContext ctx) { 1658 return flattenedTree(ctx); 1659 } 1660 1661 @Override 1662 public DetailAstImpl visitFormalLambdaParam(JavaLanguageParser.FormalLambdaParamContext ctx) { 1663 final DetailAstImpl lparen = create(ctx.LPAREN()); 1664 1665 // We add an 'PARAMETERS' node here whether it exists or not 1666 final DetailAstImpl parameters = Optional.ofNullable(visit(ctx.formalParameterList())) 1667 .orElseGet(() -> createImaginary(TokenTypes.PARAMETERS)); 1668 addLastSibling(lparen, parameters); 1669 addLastSibling(lparen, create(ctx.RPAREN())); 1670 return lparen; 1671 } 1672 1673 @Override 1674 public DetailAstImpl visitMultiLambdaParam(JavaLanguageParser.MultiLambdaParamContext ctx) { 1675 final DetailAstImpl lparen = create(ctx.LPAREN()); 1676 addLastSibling(lparen, visit(ctx.multiLambdaParams())); 1677 addLastSibling(lparen, create(ctx.RPAREN())); 1678 return lparen; 1679 } 1680 1681 @Override 1682 public DetailAstImpl visitMultiLambdaParams(JavaLanguageParser.MultiLambdaParamsContext ctx) { 1683 final DetailAstImpl parameters = createImaginary(TokenTypes.PARAMETERS); 1684 parameters.addChild(createLambdaParameter(ctx.id(0))); 1685 1686 for (int i = 0; i < ctx.COMMA().size(); i++) { 1687 parameters.addChild(create(ctx.COMMA(i))); 1688 parameters.addChild(createLambdaParameter(ctx.id(i + 1))); 1689 } 1690 return parameters; 1691 } 1692 1693 /** 1694 * Creates a 'PARAMETER_DEF' node for a lambda expression, with 1695 * imaginary modifier and type nodes. 1696 * 1697 * @param ctx the IdContext to create imaginary nodes for 1698 * @return DetailAstImpl of lambda parameter 1699 */ 1700 private DetailAstImpl createLambdaParameter(JavaLanguageParser.IdContext ctx) { 1701 final DetailAstImpl ident = visitId(ctx); 1702 final DetailAstImpl parameter = createImaginary(TokenTypes.PARAMETER_DEF); 1703 final DetailAstImpl modifiers = createImaginary(TokenTypes.MODIFIERS); 1704 final DetailAstImpl type = createImaginary(TokenTypes.TYPE); 1705 parameter.addChild(modifiers); 1706 parameter.addChild(type); 1707 parameter.addChild(ident); 1708 return parameter; 1709 } 1710 1711 @Override 1712 public DetailAstImpl visitParenPrimary(JavaLanguageParser.ParenPrimaryContext ctx) { 1713 return flattenedTree(ctx); 1714 } 1715 1716 @Override 1717 public DetailAstImpl visitTokenPrimary(JavaLanguageParser.TokenPrimaryContext ctx) { 1718 return flattenedTree(ctx); 1719 } 1720 1721 @Override 1722 public DetailAstImpl visitClassRefPrimary(JavaLanguageParser.ClassRefPrimaryContext ctx) { 1723 final DetailAstImpl dot = create(ctx.DOT()); 1724 final DetailAstImpl primaryTypeNoArray = visit(ctx.type); 1725 dot.addChild(primaryTypeNoArray); 1726 if (TokenUtil.isOfType(primaryTypeNoArray, TokenTypes.DOT)) { 1727 // We append '[]' to the qualified name 'TYPE' `ast 1728 ctx.arrayDeclarator() 1729 .forEach(child -> primaryTypeNoArray.addChild(visit(child))); 1730 } 1731 else { 1732 ctx.arrayDeclarator() 1733 .forEach(child -> addLastSibling(primaryTypeNoArray, visit(child))); 1734 } 1735 dot.addChild(create(ctx.LITERAL_CLASS())); 1736 return dot; 1737 } 1738 1739 @Override 1740 public DetailAstImpl visitPrimitivePrimary(JavaLanguageParser.PrimitivePrimaryContext ctx) { 1741 final DetailAstImpl dot = create(ctx.DOT()); 1742 final DetailAstImpl primaryTypeNoArray = visit(ctx.type); 1743 dot.addChild(primaryTypeNoArray); 1744 ctx.arrayDeclarator().forEach(child -> dot.addChild(visit(child))); 1745 dot.addChild(create(ctx.LITERAL_CLASS())); 1746 return dot; 1747 } 1748 1749 @Override 1750 public DetailAstImpl visitCreator(JavaLanguageParser.CreatorContext ctx) { 1751 return flattenedTree(ctx); 1752 } 1753 1754 @Override 1755 public DetailAstImpl visitCreatedNameObject(JavaLanguageParser.CreatedNameObjectContext ctx) { 1756 final DetailAstPair currentAST = new DetailAstPair(); 1757 DetailAstPair.addAstChild(currentAST, visit(ctx.annotations())); 1758 DetailAstPair.addAstChild(currentAST, visit(ctx.id())); 1759 DetailAstPair.addAstChild(currentAST, visit(ctx.typeArgumentsOrDiamond())); 1760 1761 // This is how we build the type arguments/ qualified name tree 1762 for (ParserRuleContext extendedContext : ctx.extended) { 1763 final DetailAstImpl dot = create(extendedContext.start); 1764 DetailAstPair.makeAstRoot(currentAST, dot); 1765 final List<ParseTree> childList = extendedContext 1766 .children.subList(1, extendedContext.children.size()); 1767 processChildren(dot, childList); 1768 } 1769 1770 return currentAST.root; 1771 } 1772 1773 @Override 1774 public DetailAstImpl visitCreatedNamePrimitive( 1775 JavaLanguageParser.CreatedNamePrimitiveContext ctx) { 1776 return flattenedTree(ctx); 1777 } 1778 1779 @Override 1780 public DetailAstImpl visitInnerCreator(JavaLanguageParser.InnerCreatorContext ctx) { 1781 return flattenedTree(ctx); 1782 } 1783 1784 @Override 1785 public DetailAstImpl visitArrayCreatorRest(JavaLanguageParser.ArrayCreatorRestContext ctx) { 1786 final DetailAstImpl arrayDeclarator = create(TokenTypes.ARRAY_DECLARATOR, 1787 (Token) ctx.LBRACK().getPayload()); 1788 final JavaLanguageParser.ExpressionContext expression = ctx.expression(); 1789 final TerminalNode rbrack = ctx.RBRACK(); 1790 // child[0] is LBRACK 1791 for (int i = 1; i < ctx.children.size(); i++) { 1792 if (ctx.children.get(i) == rbrack) { 1793 arrayDeclarator.addChild(create(rbrack)); 1794 } 1795 else if (ctx.children.get(i) == expression) { 1796 // Handle '[8]', etc. 1797 arrayDeclarator.addChild(visit(expression)); 1798 } 1799 else { 1800 addLastSibling(arrayDeclarator, visit(ctx.children.get(i))); 1801 } 1802 } 1803 return arrayDeclarator; 1804 } 1805 1806 @Override 1807 public DetailAstImpl visitBracketsWithExp(JavaLanguageParser.BracketsWithExpContext ctx) { 1808 final DetailAstImpl dummyRoot = new DetailAstImpl(); 1809 dummyRoot.addChild(visit(ctx.annotations())); 1810 final DetailAstImpl arrayDeclarator = 1811 create(TokenTypes.ARRAY_DECLARATOR, (Token) ctx.LBRACK().getPayload()); 1812 arrayDeclarator.addChild(visit(ctx.expression())); 1813 arrayDeclarator.addChild(create(ctx.stop)); 1814 dummyRoot.addChild(arrayDeclarator); 1815 return dummyRoot.getFirstChild(); 1816 } 1817 1818 @Override 1819 public DetailAstImpl visitClassCreatorRest(JavaLanguageParser.ClassCreatorRestContext ctx) { 1820 return flattenedTree(ctx); 1821 } 1822 1823 @Override 1824 public DetailAstImpl visitDiamond(JavaLanguageParser.DiamondContext ctx) { 1825 final DetailAstImpl typeArguments = 1826 createImaginary(TokenTypes.TYPE_ARGUMENTS); 1827 typeArguments.addChild(create(TokenTypes.GENERIC_START, 1828 (Token) ctx.LT().getPayload())); 1829 typeArguments.addChild(create(TokenTypes.GENERIC_END, 1830 (Token) ctx.GT().getPayload())); 1831 return typeArguments; 1832 } 1833 1834 @Override 1835 public DetailAstImpl visitTypeArgs(JavaLanguageParser.TypeArgsContext ctx) { 1836 return flattenedTree(ctx); 1837 } 1838 1839 @Override 1840 public DetailAstImpl visitNonWildcardDiamond( 1841 JavaLanguageParser.NonWildcardDiamondContext ctx) { 1842 final DetailAstImpl typeArguments = 1843 createImaginary(TokenTypes.TYPE_ARGUMENTS); 1844 typeArguments.addChild(create(TokenTypes.GENERIC_START, 1845 (Token) ctx.LT().getPayload())); 1846 typeArguments.addChild(create(TokenTypes.GENERIC_END, 1847 (Token) ctx.GT().getPayload())); 1848 return typeArguments; 1849 } 1850 1851 @Override 1852 public DetailAstImpl visitNonWildcardTypeArguments( 1853 JavaLanguageParser.NonWildcardTypeArgumentsContext ctx) { 1854 final DetailAstImpl typeArguments = createImaginary(TokenTypes.TYPE_ARGUMENTS); 1855 typeArguments.addChild(create(TokenTypes.GENERIC_START, (Token) ctx.LT().getPayload())); 1856 typeArguments.addChild(visit(ctx.typeArgumentsTypeList())); 1857 typeArguments.addChild(create(TokenTypes.GENERIC_END, (Token) ctx.GT().getPayload())); 1858 return typeArguments; 1859 } 1860 1861 @Override 1862 public DetailAstImpl visitTypeArgumentsTypeList( 1863 JavaLanguageParser.TypeArgumentsTypeListContext ctx) { 1864 final DetailAstImpl firstIdent = visit(ctx.typeType(0)); 1865 final DetailAstImpl firstTypeArgument = createImaginary(TokenTypes.TYPE_ARGUMENT); 1866 firstTypeArgument.addChild(firstIdent); 1867 1868 for (int i = 0; i < ctx.COMMA().size(); i++) { 1869 addLastSibling(firstTypeArgument, create(ctx.COMMA(i))); 1870 final DetailAstImpl ident = visit(ctx.typeType(i + 1)); 1871 final DetailAstImpl typeArgument = createImaginary(TokenTypes.TYPE_ARGUMENT); 1872 typeArgument.addChild(ident); 1873 addLastSibling(firstTypeArgument, typeArgument); 1874 } 1875 return firstTypeArgument; 1876 } 1877 1878 @Override 1879 public DetailAstImpl visitTypeList(JavaLanguageParser.TypeListContext ctx) { 1880 return flattenedTree(ctx); 1881 } 1882 1883 @Override 1884 public DetailAstImpl visitTypeType(JavaLanguageParser.TypeTypeContext ctx) { 1885 final DetailAstImpl type = createImaginary(TokenTypes.TYPE); 1886 processChildren(type, ctx.children); 1887 1888 final DetailAstImpl returnTree; 1889 if (ctx.createImaginaryNode) { 1890 returnTree = type; 1891 } 1892 else { 1893 returnTree = type.getFirstChild(); 1894 } 1895 return returnTree; 1896 } 1897 1898 @Override 1899 public DetailAstImpl visitArrayDeclarator(JavaLanguageParser.ArrayDeclaratorContext ctx) { 1900 final DetailAstImpl arrayDeclarator = create(TokenTypes.ARRAY_DECLARATOR, 1901 (Token) ctx.LBRACK().getPayload()); 1902 arrayDeclarator.addChild(create(ctx.RBRACK())); 1903 1904 final DetailAstImpl returnTree; 1905 final DetailAstImpl annotations = visit(ctx.anno); 1906 if (annotations == null) { 1907 returnTree = arrayDeclarator; 1908 } 1909 else { 1910 returnTree = annotations; 1911 addLastSibling(returnTree, arrayDeclarator); 1912 } 1913 return returnTree; 1914 } 1915 1916 @Override 1917 public DetailAstImpl visitPrimitiveType(JavaLanguageParser.PrimitiveTypeContext ctx) { 1918 return create(ctx.start); 1919 } 1920 1921 @Override 1922 public DetailAstImpl visitTypeArguments(JavaLanguageParser.TypeArgumentsContext ctx) { 1923 final DetailAstImpl typeArguments = createImaginary(TokenTypes.TYPE_ARGUMENTS); 1924 typeArguments.addChild(create(TokenTypes.GENERIC_START, (Token) ctx.LT().getPayload())); 1925 // Exclude '<' and '>' 1926 processChildren(typeArguments, ctx.children.subList(1, ctx.children.size() - 1)); 1927 typeArguments.addChild(create(TokenTypes.GENERIC_END, (Token) ctx.GT().getPayload())); 1928 return typeArguments; 1929 } 1930 1931 @Override 1932 public DetailAstImpl visitSuperSuffixDot(JavaLanguageParser.SuperSuffixDotContext ctx) { 1933 final DetailAstImpl root; 1934 if (ctx.LPAREN() == null) { 1935 root = create(ctx.DOT()); 1936 root.addChild(visit(ctx.id())); 1937 } 1938 else { 1939 root = create(TokenTypes.METHOD_CALL, (Token) ctx.LPAREN().getPayload()); 1940 1941 final DetailAstImpl dot = create(ctx.DOT()); 1942 dot.addChild(visit(ctx.id())); 1943 root.addChild(dot); 1944 1945 final DetailAstImpl expressionList = Optional.ofNullable(visit(ctx.expressionList())) 1946 .orElseGet(() -> createImaginary(TokenTypes.ELIST)); 1947 root.addChild(expressionList); 1948 1949 root.addChild(create(ctx.RPAREN())); 1950 } 1951 1952 return root; 1953 } 1954 1955 @Override 1956 public DetailAstImpl visitArguments(JavaLanguageParser.ArgumentsContext ctx) { 1957 final DetailAstImpl lparen = create(ctx.LPAREN()); 1958 1959 // We always add an 'ELIST' node 1960 final DetailAstImpl expressionList = Optional.ofNullable(visit(ctx.expressionList())) 1961 .orElseGet(() -> createImaginary(TokenTypes.ELIST)); 1962 addLastSibling(lparen, expressionList); 1963 addLastSibling(lparen, create(ctx.RPAREN())); 1964 return lparen; 1965 } 1966 1967 @Override 1968 public DetailAstImpl visitPattern(JavaLanguageParser.PatternContext ctx) { 1969 final JavaLanguageParser.InnerPatternContext innerPattern = ctx.innerPattern(); 1970 final ParserRuleContext primaryPattern = innerPattern.primaryPattern(); 1971 final ParserRuleContext recordPattern = innerPattern.recordPattern(); 1972 final boolean isSimpleTypePattern = primaryPattern != null 1973 && primaryPattern.getChild(0) instanceof JavaLanguageParser.TypePatternContext; 1974 1975 final DetailAstImpl pattern; 1976 1977 if (recordPattern != null) { 1978 pattern = visit(recordPattern); 1979 } 1980 else if (isSimpleTypePattern) { 1981 // For simple type pattern like 'Integer i`, we do not add `PATTERN_DEF` parent 1982 pattern = visit(primaryPattern); 1983 } 1984 else { 1985 pattern = createImaginary(TokenTypes.PATTERN_DEF); 1986 pattern.addChild(visit(ctx.getChild(0))); 1987 } 1988 return pattern; 1989 } 1990 1991 @Override 1992 public DetailAstImpl visitInnerPattern(JavaLanguageParser.InnerPatternContext ctx) { 1993 return flattenedTree(ctx); 1994 } 1995 1996 @Override 1997 public DetailAstImpl visitGuardedPattern(JavaLanguageParser.GuardedPatternContext ctx) { 1998 final DetailAstImpl guardAstNode = flattenedTree(ctx.guard()); 1999 guardAstNode.addChild(visit(ctx.primaryPattern())); 2000 guardAstNode.addChild(visit(ctx.expression())); 2001 return guardAstNode; 2002 } 2003 2004 @Override 2005 public DetailAstImpl visitParenPattern(JavaLanguageParser.ParenPatternContext ctx) { 2006 final DetailAstImpl lparen = create(ctx.LPAREN()); 2007 final ParseTree innerPattern = ctx.getChild(1); 2008 lparen.addChild(visit(innerPattern)); 2009 lparen.addChild(create(ctx.RPAREN())); 2010 return lparen; 2011 } 2012 2013 @Override 2014 public DetailAstImpl visitRecordPatternDef(JavaLanguageParser.RecordPatternDefContext ctx) { 2015 return flattenedTree(ctx); 2016 } 2017 2018 @Override 2019 public DetailAstImpl visitTypePatternDef( 2020 JavaLanguageParser.TypePatternDefContext ctx) { 2021 final DetailAstImpl type = visit(ctx.type); 2022 final DetailAstImpl patternVariableDef = createImaginary(TokenTypes.PATTERN_VARIABLE_DEF); 2023 patternVariableDef.addChild(createModifiers(ctx.mods)); 2024 patternVariableDef.addChild(type); 2025 patternVariableDef.addChild(visit(ctx.id())); 2026 return patternVariableDef; 2027 } 2028 2029 @Override 2030 public DetailAstImpl visitUnnamedPatternDef(JavaLanguageParser.UnnamedPatternDefContext ctx) { 2031 return create(TokenTypes.UNNAMED_PATTERN_DEF, ctx.start); 2032 } 2033 2034 @Override 2035 public DetailAstImpl visitRecordPattern(JavaLanguageParser.RecordPatternContext ctx) { 2036 final DetailAstImpl recordPattern = createImaginary(TokenTypes.RECORD_PATTERN_DEF); 2037 recordPattern.addChild(createModifiers(ctx.mods)); 2038 processChildren(recordPattern, 2039 ctx.children.subList(ctx.mods.size(), ctx.children.size())); 2040 return recordPattern; 2041 } 2042 2043 @Override 2044 public DetailAstImpl visitRecordComponentPatternList( 2045 JavaLanguageParser.RecordComponentPatternListContext ctx) { 2046 final DetailAstImpl recordComponents = 2047 createImaginary(TokenTypes.RECORD_PATTERN_COMPONENTS); 2048 processChildren(recordComponents, ctx.children); 2049 return recordComponents; 2050 } 2051 2052 @Override 2053 public DetailAstImpl visitPermittedSubclassesAndInterfaces( 2054 JavaLanguageParser.PermittedSubclassesAndInterfacesContext ctx) { 2055 final DetailAstImpl literalPermits = 2056 create(TokenTypes.PERMITS_CLAUSE, (Token) ctx.LITERAL_PERMITS().getPayload()); 2057 // 'LITERAL_PERMITS' is child[0] 2058 processChildren(literalPermits, ctx.children.subList(1, ctx.children.size())); 2059 return literalPermits; 2060 } 2061 2062 @Override 2063 public DetailAstImpl visitId(JavaLanguageParser.IdContext ctx) { 2064 return create(TokenTypes.IDENT, ctx.start); 2065 } 2066 2067 /** 2068 * Builds the AST for a particular node, then returns a "flattened" tree 2069 * of siblings. This method should be used in rule contexts such as 2070 * {@code variableDeclarators}, where we have both terminals and non-terminals. 2071 * 2072 * @param ctx the ParserRuleContext to base tree on 2073 * @return flattened DetailAstImpl 2074 */ 2075 private DetailAstImpl flattenedTree(ParserRuleContext ctx) { 2076 final DetailAstImpl dummyNode = new DetailAstImpl(); 2077 processChildren(dummyNode, ctx.children); 2078 return dummyNode.getFirstChild(); 2079 } 2080 2081 /** 2082 * Adds all the children from the given ParseTree or JavaParserContext 2083 * list to the parent DetailAstImpl. 2084 * 2085 * @param parent the DetailAstImpl to add children to 2086 * @param children the list of children to add 2087 */ 2088 private void processChildren(DetailAstImpl parent, List<? extends ParseTree> children) { 2089 children.forEach(child -> { 2090 if (child instanceof TerminalNode) { 2091 // Child is a token, create a new DetailAstImpl and add it to parent 2092 parent.addChild(create((TerminalNode) child)); 2093 } 2094 else { 2095 // Child is another rule context; visit it, create token, and add to parent 2096 parent.addChild(visit(child)); 2097 } 2098 }); 2099 } 2100 2101 /** 2102 * Create a DetailAstImpl from a given token and token type. This method 2103 * should be used for imaginary nodes only, i.e. 'OBJBLOCK -> OBJBLOCK', 2104 * where the text on the RHS matches the text on the LHS. 2105 * 2106 * @param tokenType the token type of this DetailAstImpl 2107 * @return new DetailAstImpl of given type 2108 */ 2109 private static DetailAstImpl createImaginary(int tokenType) { 2110 final DetailAstImpl detailAst = new DetailAstImpl(); 2111 detailAst.setType(tokenType); 2112 detailAst.setText(TokenUtil.getTokenName(tokenType)); 2113 return detailAst; 2114 } 2115 2116 /** 2117 * Create a DetailAstImpl from a given token and token type. This method 2118 * should be used for literal nodes only, i.e. 'PACKAGE_DEF -> package'. 2119 * 2120 * @param tokenType the token type of this DetailAstImpl 2121 * @param startToken the first token that appears in this DetailAstImpl. 2122 * @return new DetailAstImpl of given type 2123 */ 2124 private DetailAstImpl create(int tokenType, Token startToken) { 2125 final DetailAstImpl ast = create(startToken); 2126 ast.setType(tokenType); 2127 return ast; 2128 } 2129 2130 /** 2131 * Create a DetailAstImpl from a given token. This method should be 2132 * used for terminal nodes, i.e. {@code LCURLY}, when we are building 2133 * an AST for a specific token, regardless of position. 2134 * 2135 * @param token the token to build the DetailAstImpl from 2136 * @return new DetailAstImpl of given type 2137 */ 2138 private DetailAstImpl create(Token token) { 2139 final int tokenIndex = token.getTokenIndex(); 2140 final List<Token> tokensToLeft = 2141 tokens.getHiddenTokensToLeft(tokenIndex, JavaLanguageLexer.COMMENTS); 2142 final List<Token> tokensToRight = 2143 tokens.getHiddenTokensToRight(tokenIndex, JavaLanguageLexer.COMMENTS); 2144 2145 final DetailAstImpl detailAst = new DetailAstImpl(); 2146 detailAst.initialize(token); 2147 if (tokensToLeft != null) { 2148 detailAst.setHiddenBefore(tokensToLeft); 2149 } 2150 if (tokensToRight != null) { 2151 detailAst.setHiddenAfter(tokensToRight); 2152 } 2153 return detailAst; 2154 } 2155 2156 /** 2157 * Create a DetailAstImpl from a given TerminalNode. This method should be 2158 * used for terminal nodes, i.e. {@code @}. 2159 * 2160 * @param node the TerminalNode to build the DetailAstImpl from 2161 * @return new DetailAstImpl of given type 2162 */ 2163 private DetailAstImpl create(TerminalNode node) { 2164 return create((Token) node.getPayload()); 2165 } 2166 2167 /** 2168 * Creates a type declaration DetailAstImpl from a given rule context. 2169 * 2170 * @param ctx ParserRuleContext we are in 2171 * @param type the type declaration to create 2172 * @param modifierList respective modifiers 2173 * @return type declaration DetailAstImpl 2174 */ 2175 private DetailAstImpl createTypeDeclaration(ParserRuleContext ctx, int type, 2176 List<? extends ParseTree> modifierList) { 2177 final DetailAstImpl typeDeclaration = createImaginary(type); 2178 typeDeclaration.addChild(createModifiers(modifierList)); 2179 processChildren(typeDeclaration, ctx.children); 2180 return typeDeclaration; 2181 } 2182 2183 /** 2184 * Builds the modifiers AST. 2185 * 2186 * @param modifierList the list of modifier contexts 2187 * @return "MODIFIERS" ast 2188 */ 2189 private DetailAstImpl createModifiers(List<? extends ParseTree> modifierList) { 2190 final DetailAstImpl mods = createImaginary(TokenTypes.MODIFIERS); 2191 processChildren(mods, modifierList); 2192 return mods; 2193 } 2194 2195 /** 2196 * Add new sibling to the end of existing siblings. 2197 * 2198 * @param self DetailAstImpl to add last sibling to 2199 * @param sibling DetailAstImpl sibling to add 2200 */ 2201 private static void addLastSibling(DetailAstImpl self, DetailAstImpl sibling) { 2202 DetailAstImpl nextSibling = self; 2203 if (nextSibling != null) { 2204 while (nextSibling.getNextSibling() != null) { 2205 nextSibling = nextSibling.getNextSibling(); 2206 } 2207 nextSibling.setNextSibling(sibling); 2208 } 2209 } 2210 2211 @Override 2212 public DetailAstImpl visit(ParseTree tree) { 2213 DetailAstImpl ast = null; 2214 if (tree != null) { 2215 ast = tree.accept(this); 2216 } 2217 return ast; 2218 } 2219 2220 /** 2221 * Builds an expression node. This is used to build the root of an expression with 2222 * an imaginary {@code EXPR} node. 2223 * 2224 * @param exprNode expression to build node for 2225 * @return expression DetailAstImpl node 2226 */ 2227 private DetailAstImpl buildExpressionNode(ParseTree exprNode) { 2228 final DetailAstImpl expression = visit(exprNode); 2229 2230 final DetailAstImpl exprRoot; 2231 if (TokenUtil.isOfType(expression, EXPRESSIONS_WITH_NO_EXPR_ROOT)) { 2232 exprRoot = expression; 2233 } 2234 else { 2235 // create imaginary 'EXPR' node as root of expression 2236 exprRoot = createImaginary(TokenTypes.EXPR); 2237 exprRoot.addChild(expression); 2238 } 2239 return exprRoot; 2240 } 2241 2242 /** 2243 * Used to swap and organize DetailAstImpl subtrees. 2244 */ 2245 private static final class DetailAstPair { 2246 2247 /** The root DetailAstImpl of this pair. */ 2248 private DetailAstImpl root; 2249 2250 /** The child (potentially with siblings) of this pair. */ 2251 private DetailAstImpl child; 2252 2253 /** 2254 * Moves child reference to the last child. 2255 */ 2256 private void advanceChildToEnd() { 2257 while (child.getNextSibling() != null) { 2258 child = child.getNextSibling(); 2259 } 2260 } 2261 2262 /** 2263 * Returns the root node. 2264 * 2265 * @return the root node 2266 */ 2267 private DetailAstImpl getRoot() { 2268 return root; 2269 } 2270 2271 /** 2272 * This method is used to replace the {@code ^} (set as root node) ANTLR2 2273 * operator. 2274 * 2275 * @param pair the DetailAstPair to use for swapping nodes 2276 * @param ast the new root 2277 */ 2278 private static void makeAstRoot(DetailAstPair pair, DetailAstImpl ast) { 2279 ast.addChild(pair.root); 2280 pair.child = pair.root; 2281 pair.advanceChildToEnd(); 2282 pair.root = ast; 2283 } 2284 2285 /** 2286 * Adds a child (or new root) to the given DetailAstPair. 2287 * 2288 * @param pair the DetailAstPair to add child to 2289 * @param ast the child to add 2290 */ 2291 private static void addAstChild(DetailAstPair pair, DetailAstImpl ast) { 2292 if (ast != null) { 2293 if (pair.root == null) { 2294 pair.root = ast; 2295 } 2296 else { 2297 pair.child.setNextSibling(ast); 2298 } 2299 pair.child = ast; 2300 } 2301 } 2302 } 2303}