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.Objects; 027import java.util.Optional; 028import java.util.Queue; 029import java.util.concurrent.ConcurrentLinkedQueue; 030import java.util.stream.Collectors; 031 032import org.antlr.v4.runtime.BufferedTokenStream; 033import org.antlr.v4.runtime.CommonTokenStream; 034import org.antlr.v4.runtime.ParserRuleContext; 035import org.antlr.v4.runtime.Token; 036import org.antlr.v4.runtime.tree.ParseTree; 037import org.antlr.v4.runtime.tree.TerminalNode; 038 039import com.puppycrawl.tools.checkstyle.api.TokenTypes; 040import com.puppycrawl.tools.checkstyle.grammar.java.JavaLanguageLexer; 041import com.puppycrawl.tools.checkstyle.grammar.java.JavaLanguageParser; 042import com.puppycrawl.tools.checkstyle.grammar.java.JavaLanguageParserBaseVisitor; 043import com.puppycrawl.tools.checkstyle.utils.TokenUtil; 044 045/** 046 * Visitor class used to build Checkstyle's Java AST from the parse tree produced by 047 * {@link JavaLanguageParser}. In each {@code visit...} method, we visit the children of a node 048 * (which correspond to subrules) or create terminal nodes (tokens), and return a subtree as a 049 * result. 050 * 051 * <p>Example:</p> 052 * 053 * <p>The following package declaration:</p> 054 * <pre> 055 * package com.puppycrawl.tools.checkstyle; 056 * </pre> 057 * 058 * <p> 059 * Will be parsed by the {@code packageDeclaration} rule from {@code JavaLanguageParser.g4}: 060 * </p> 061 * <pre> 062 * packageDeclaration 063 * : annotations[true] LITERAL_PACKAGE qualifiedName SEMI 064 * ; 065 * </pre> 066 * 067 * <p> 068 * We override the {@code visitPackageDeclaration} method generated by ANTLR in 069 * {@link JavaLanguageParser} at 070 * {@link JavaAstVisitor#visitPackageDeclaration(JavaLanguageParser.PackageDeclarationContext)} 071 * to create a subtree based on the subrules and tokens found in the {@code packageDeclaration} 072 * subrule accordingly, thus producing the following AST: 073 * </p> 074 * <pre> 075 * PACKAGE_DEF -> package 076 * |--ANNOTATIONS -> ANNOTATIONS 077 * |--DOT -> . 078 * | |--DOT -> . 079 * | | |--DOT -> . 080 * | | | |--IDENT -> com 081 * | | | `--IDENT -> puppycrawl 082 * | | `--IDENT -> tools 083 * | `--IDENT -> checkstyle 084 * `--SEMI -> ; 085 * </pre> 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 * <p> 092 * The order of {@code visit...} methods in {@code JavaAstVisitor.java} and production rules in 093 * {@code JavaLanguageParser.g4} should be consistent to ease maintenance. 094 * </p> 095 */ 096public final class JavaAstVisitor extends JavaLanguageParserBaseVisitor<DetailAstImpl> { 097 098 /** String representation of the left shift operator. */ 099 private static final String LEFT_SHIFT = "<<"; 100 101 /** String representation of the unsigned right shift operator. */ 102 private static final String UNSIGNED_RIGHT_SHIFT = ">>>"; 103 104 /** String representation of the right shift operator. */ 105 private static final String RIGHT_SHIFT = ">>"; 106 107 /** String representation of the double quote character. */ 108 private static final String QUOTE = "\""; 109 110 /** 111 * The tokens here are technically expressions, but should 112 * not return an EXPR token as their root. 113 */ 114 private static final int[] EXPRESSIONS_WITH_NO_EXPR_ROOT = { 115 TokenTypes.CTOR_CALL, 116 TokenTypes.SUPER_CTOR_CALL, 117 TokenTypes.LAMBDA, 118 }; 119 120 /** Token stream to check for hidden tokens. */ 121 private final BufferedTokenStream tokens; 122 123 /** 124 * Constructs a JavaAstVisitor with given token stream. 125 * 126 * @param tokenStream the token stream to check for hidden tokens 127 */ 128 public JavaAstVisitor(CommonTokenStream tokenStream) { 129 tokens = tokenStream; 130 } 131 132 @Override 133 public DetailAstImpl visitCompilationUnit(JavaLanguageParser.CompilationUnitContext ctx) { 134 final DetailAstImpl compilationUnit; 135 // 'EOF' token is always present; therefore if we only have one child, we have an empty file 136 final boolean isEmptyFile = ctx.children.size() == 1; 137 if (isEmptyFile) { 138 compilationUnit = null; 139 } 140 else { 141 compilationUnit = createImaginary(TokenTypes.COMPILATION_UNIT); 142 // last child is 'EOF', we do not include this token in AST 143 processChildren(compilationUnit, ctx.children.subList(0, ctx.children.size() - 1)); 144 } 145 return compilationUnit; 146 } 147 148 @Override 149 public DetailAstImpl visitPackageDeclaration( 150 JavaLanguageParser.PackageDeclarationContext ctx) { 151 final DetailAstImpl packageDeclaration = 152 create(TokenTypes.PACKAGE_DEF, (Token) ctx.LITERAL_PACKAGE().getPayload()); 153 packageDeclaration.addChild(visit(ctx.annotations())); 154 packageDeclaration.addChild(visit(ctx.qualifiedName())); 155 packageDeclaration.addChild(create(ctx.SEMI())); 156 return packageDeclaration; 157 } 158 159 @Override 160 public DetailAstImpl visitImportDec(JavaLanguageParser.ImportDecContext ctx) { 161 final DetailAstImpl importRoot = create(ctx.start); 162 163 // Static import 164 final TerminalNode literalStaticNode = ctx.LITERAL_STATIC(); 165 if (literalStaticNode != null) { 166 importRoot.setType(TokenTypes.STATIC_IMPORT); 167 importRoot.addChild(create(literalStaticNode)); 168 } 169 170 // Handle star imports 171 final boolean isStarImport = ctx.STAR() != null; 172 if (isStarImport) { 173 final DetailAstImpl dot = create(ctx.DOT()); 174 dot.addChild(visit(ctx.qualifiedName())); 175 dot.addChild(create(ctx.STAR())); 176 importRoot.addChild(dot); 177 } 178 else { 179 importRoot.addChild(visit(ctx.qualifiedName())); 180 } 181 182 importRoot.addChild(create(ctx.SEMI())); 183 return importRoot; 184 } 185 186 @Override 187 public DetailAstImpl visitSingleSemiImport(JavaLanguageParser.SingleSemiImportContext ctx) { 188 return create(ctx.SEMI()); 189 } 190 191 @Override 192 public DetailAstImpl visitTypeDeclaration(JavaLanguageParser.TypeDeclarationContext ctx) { 193 final DetailAstImpl typeDeclaration; 194 if (ctx.type == null) { 195 typeDeclaration = create(ctx.semi.get(0)); 196 ctx.semi.subList(1, ctx.semi.size()) 197 .forEach(semi -> addLastSibling(typeDeclaration, create(semi))); 198 } 199 else { 200 typeDeclaration = visit(ctx.type); 201 } 202 return typeDeclaration; 203 } 204 205 @Override 206 public DetailAstImpl visitModifier(JavaLanguageParser.ModifierContext ctx) { 207 return flattenedTree(ctx); 208 } 209 210 @Override 211 public DetailAstImpl visitVariableModifier(JavaLanguageParser.VariableModifierContext ctx) { 212 return flattenedTree(ctx); 213 } 214 215 @Override 216 public DetailAstImpl visitClassDeclaration(JavaLanguageParser.ClassDeclarationContext ctx) { 217 return createTypeDeclaration(ctx, TokenTypes.CLASS_DEF, ctx.mods); 218 } 219 220 @Override 221 public DetailAstImpl visitRecordDeclaration(JavaLanguageParser.RecordDeclarationContext ctx) { 222 return createTypeDeclaration(ctx, TokenTypes.RECORD_DEF, ctx.mods); 223 } 224 225 @Override 226 public DetailAstImpl visitRecordComponentsList( 227 JavaLanguageParser.RecordComponentsListContext ctx) { 228 final DetailAstImpl lparen = create(ctx.LPAREN()); 229 230 // We make a "RECORD_COMPONENTS" node whether components exist or not 231 if (ctx.recordComponents() == null) { 232 addLastSibling(lparen, createImaginary(TokenTypes.RECORD_COMPONENTS)); 233 } 234 else { 235 addLastSibling(lparen, visit(ctx.recordComponents())); 236 } 237 addLastSibling(lparen, create(ctx.RPAREN())); 238 return lparen; 239 } 240 241 @Override 242 public DetailAstImpl visitRecordComponents(JavaLanguageParser.RecordComponentsContext ctx) { 243 final DetailAstImpl recordComponents = createImaginary(TokenTypes.RECORD_COMPONENTS); 244 processChildren(recordComponents, ctx.children); 245 return recordComponents; 246 } 247 248 @Override 249 public DetailAstImpl visitRecordComponent(JavaLanguageParser.RecordComponentContext ctx) { 250 final DetailAstImpl recordComponent = createImaginary(TokenTypes.RECORD_COMPONENT_DEF); 251 processChildren(recordComponent, ctx.children); 252 return recordComponent; 253 } 254 255 @Override 256 public DetailAstImpl visitLastRecordComponent( 257 JavaLanguageParser.LastRecordComponentContext ctx) { 258 final DetailAstImpl recordComponent = createImaginary(TokenTypes.RECORD_COMPONENT_DEF); 259 processChildren(recordComponent, ctx.children); 260 return recordComponent; 261 } 262 263 @Override 264 public DetailAstImpl visitRecordBody(JavaLanguageParser.RecordBodyContext ctx) { 265 final DetailAstImpl objBlock = createImaginary(TokenTypes.OBJBLOCK); 266 processChildren(objBlock, ctx.children); 267 return objBlock; 268 } 269 270 @Override 271 public DetailAstImpl visitCompactConstructorDeclaration( 272 JavaLanguageParser.CompactConstructorDeclarationContext ctx) { 273 final DetailAstImpl compactConstructor = createImaginary(TokenTypes.COMPACT_CTOR_DEF); 274 compactConstructor.addChild(createModifiers(ctx.mods)); 275 compactConstructor.addChild(visit(ctx.id())); 276 compactConstructor.addChild(visit(ctx.constructorBlock())); 277 return compactConstructor; 278 } 279 280 @Override 281 public DetailAstImpl visitClassExtends(JavaLanguageParser.ClassExtendsContext ctx) { 282 final DetailAstImpl classExtends = create(ctx.EXTENDS_CLAUSE()); 283 classExtends.addChild(visit(ctx.type)); 284 return classExtends; 285 } 286 287 @Override 288 public DetailAstImpl visitImplementsClause(JavaLanguageParser.ImplementsClauseContext ctx) { 289 final DetailAstImpl classImplements = create(TokenTypes.IMPLEMENTS_CLAUSE, 290 (Token) ctx.LITERAL_IMPLEMENTS().getPayload()); 291 classImplements.addChild(visit(ctx.typeList())); 292 return classImplements; 293 } 294 295 @Override 296 public DetailAstImpl visitTypeParameters(JavaLanguageParser.TypeParametersContext ctx) { 297 final DetailAstImpl typeParameters = createImaginary(TokenTypes.TYPE_PARAMETERS); 298 typeParameters.addChild(create(TokenTypes.GENERIC_START, (Token) ctx.LT().getPayload())); 299 // Exclude '<' and '>' 300 processChildren(typeParameters, ctx.children.subList(1, ctx.children.size() - 1)); 301 typeParameters.addChild(create(TokenTypes.GENERIC_END, (Token) ctx.GT().getPayload())); 302 return typeParameters; 303 } 304 305 @Override 306 public DetailAstImpl visitTypeParameter(JavaLanguageParser.TypeParameterContext ctx) { 307 final DetailAstImpl typeParameter = createImaginary(TokenTypes.TYPE_PARAMETER); 308 processChildren(typeParameter, ctx.children); 309 return typeParameter; 310 } 311 312 @Override 313 public DetailAstImpl visitTypeUpperBounds(JavaLanguageParser.TypeUpperBoundsContext ctx) { 314 // In this case, we call 'extends` TYPE_UPPER_BOUNDS 315 final DetailAstImpl typeUpperBounds = create(TokenTypes.TYPE_UPPER_BOUNDS, 316 (Token) ctx.EXTENDS_CLAUSE().getPayload()); 317 // 'extends' is child[0] 318 processChildren(typeUpperBounds, ctx.children.subList(1, ctx.children.size())); 319 return typeUpperBounds; 320 } 321 322 @Override 323 public DetailAstImpl visitTypeBound(JavaLanguageParser.TypeBoundContext ctx) { 324 final DetailAstImpl typeBoundType = visit(ctx.typeBoundType(0)); 325 final Iterator<JavaLanguageParser.TypeBoundTypeContext> typeBoundTypeIterator = 326 ctx.typeBoundType().listIterator(1); 327 ctx.BAND().forEach(band -> { 328 addLastSibling(typeBoundType, create(TokenTypes.TYPE_EXTENSION_AND, 329 (Token) band.getPayload())); 330 addLastSibling(typeBoundType, visit(typeBoundTypeIterator.next())); 331 }); 332 return typeBoundType; 333 } 334 335 @Override 336 public DetailAstImpl visitTypeBoundType(JavaLanguageParser.TypeBoundTypeContext ctx) { 337 return flattenedTree(ctx); 338 } 339 340 @Override 341 public DetailAstImpl visitEnumDeclaration(JavaLanguageParser.EnumDeclarationContext ctx) { 342 return createTypeDeclaration(ctx, TokenTypes.ENUM_DEF, ctx.mods); 343 } 344 345 @Override 346 public DetailAstImpl visitEnumBody(JavaLanguageParser.EnumBodyContext ctx) { 347 final DetailAstImpl objBlock = createImaginary(TokenTypes.OBJBLOCK); 348 processChildren(objBlock, ctx.children); 349 return objBlock; 350 } 351 352 @Override 353 public DetailAstImpl visitEnumConstants(JavaLanguageParser.EnumConstantsContext ctx) { 354 return flattenedTree(ctx); 355 } 356 357 @Override 358 public DetailAstImpl visitEnumConstant(JavaLanguageParser.EnumConstantContext ctx) { 359 final DetailAstImpl enumConstant = 360 createImaginary(TokenTypes.ENUM_CONSTANT_DEF); 361 processChildren(enumConstant, ctx.children); 362 return enumConstant; 363 } 364 365 @Override 366 public DetailAstImpl visitEnumBodyDeclarations( 367 JavaLanguageParser.EnumBodyDeclarationsContext ctx) { 368 return flattenedTree(ctx); 369 } 370 371 @Override 372 public DetailAstImpl visitInterfaceDeclaration( 373 JavaLanguageParser.InterfaceDeclarationContext ctx) { 374 return createTypeDeclaration(ctx, TokenTypes.INTERFACE_DEF, ctx.mods); 375 } 376 377 @Override 378 public DetailAstImpl visitInterfaceExtends(JavaLanguageParser.InterfaceExtendsContext ctx) { 379 final DetailAstImpl interfaceExtends = create(ctx.EXTENDS_CLAUSE()); 380 interfaceExtends.addChild(visit(ctx.typeList())); 381 return interfaceExtends; 382 } 383 384 @Override 385 public DetailAstImpl visitClassBody(JavaLanguageParser.ClassBodyContext ctx) { 386 final DetailAstImpl objBlock = createImaginary(TokenTypes.OBJBLOCK); 387 processChildren(objBlock, ctx.children); 388 return objBlock; 389 } 390 391 @Override 392 public DetailAstImpl visitInterfaceBody(JavaLanguageParser.InterfaceBodyContext ctx) { 393 final DetailAstImpl objBlock = createImaginary(TokenTypes.OBJBLOCK); 394 processChildren(objBlock, ctx.children); 395 return objBlock; 396 } 397 398 @Override 399 public DetailAstImpl visitEmptyClass(JavaLanguageParser.EmptyClassContext ctx) { 400 return flattenedTree(ctx); 401 } 402 403 @Override 404 public DetailAstImpl visitClassBlock(JavaLanguageParser.ClassBlockContext ctx) { 405 final DetailAstImpl classBlock; 406 if (ctx.LITERAL_STATIC() == null) { 407 // We call it an INSTANCE_INIT 408 classBlock = createImaginary(TokenTypes.INSTANCE_INIT); 409 } 410 else { 411 classBlock = create(TokenTypes.STATIC_INIT, (Token) ctx.LITERAL_STATIC().getPayload()); 412 classBlock.setText(TokenUtil.getTokenName(TokenTypes.STATIC_INIT)); 413 } 414 classBlock.addChild(visit(ctx.block())); 415 return classBlock; 416 } 417 418 @Override 419 public DetailAstImpl visitMethodDeclaration(JavaLanguageParser.MethodDeclarationContext ctx) { 420 final DetailAstImpl methodDef = createImaginary(TokenTypes.METHOD_DEF); 421 methodDef.addChild(createModifiers(ctx.mods)); 422 423 // Process all children except C style array declarators 424 processChildren(methodDef, ctx.children.stream() 425 .filter(child -> !(child instanceof JavaLanguageParser.ArrayDeclaratorContext)) 426 .collect(Collectors.toUnmodifiableList())); 427 428 // We add C style array declarator brackets to TYPE ast 429 final DetailAstImpl typeAst = (DetailAstImpl) methodDef.findFirstToken(TokenTypes.TYPE); 430 ctx.cStyleArrDec.forEach(child -> typeAst.addChild(visit(child))); 431 432 return methodDef; 433 } 434 435 @Override 436 public DetailAstImpl visitMethodBody(JavaLanguageParser.MethodBodyContext ctx) { 437 return flattenedTree(ctx); 438 } 439 440 @Override 441 public DetailAstImpl visitThrowsList(JavaLanguageParser.ThrowsListContext ctx) { 442 final DetailAstImpl throwsRoot = create(ctx.LITERAL_THROWS()); 443 throwsRoot.addChild(visit(ctx.qualifiedNameList())); 444 return throwsRoot; 445 } 446 447 @Override 448 public DetailAstImpl visitConstructorDeclaration( 449 JavaLanguageParser.ConstructorDeclarationContext ctx) { 450 final DetailAstImpl constructorDeclaration = createImaginary(TokenTypes.CTOR_DEF); 451 constructorDeclaration.addChild(createModifiers(ctx.mods)); 452 processChildren(constructorDeclaration, ctx.children); 453 return constructorDeclaration; 454 } 455 456 @Override 457 public DetailAstImpl visitFieldDeclaration(JavaLanguageParser.FieldDeclarationContext ctx) { 458 final DetailAstImpl dummyNode = new DetailAstImpl(); 459 // Since the TYPE AST is built by visitVariableDeclarator(), we skip it here (child [0]) 460 // We also append the SEMI token to the first child [size() - 1], 461 // until https://github.com/checkstyle/checkstyle/issues/3151 462 processChildren(dummyNode, ctx.children.subList(1, ctx.children.size() - 1)); 463 dummyNode.getFirstChild().addChild(create(ctx.SEMI())); 464 return dummyNode.getFirstChild(); 465 } 466 467 @Override 468 public DetailAstImpl visitInterfaceBodyDeclaration( 469 JavaLanguageParser.InterfaceBodyDeclarationContext ctx) { 470 final DetailAstImpl returnTree; 471 if (ctx.SEMI() == null) { 472 returnTree = visit(ctx.interfaceMemberDeclaration()); 473 } 474 else { 475 returnTree = create(ctx.SEMI()); 476 } 477 return returnTree; 478 } 479 480 @Override 481 public DetailAstImpl visitInterfaceMethodDeclaration( 482 JavaLanguageParser.InterfaceMethodDeclarationContext ctx) { 483 final DetailAstImpl methodDef = createImaginary(TokenTypes.METHOD_DEF); 484 methodDef.addChild(createModifiers(ctx.mods)); 485 486 // Process all children except C style array declarators and modifiers 487 final List<ParseTree> children = ctx.children 488 .stream() 489 .filter(child -> !(child instanceof JavaLanguageParser.ArrayDeclaratorContext)) 490 .collect(Collectors.toUnmodifiableList()); 491 processChildren(methodDef, children); 492 493 // We add C style array declarator brackets to TYPE ast 494 final DetailAstImpl typeAst = (DetailAstImpl) methodDef.findFirstToken(TokenTypes.TYPE); 495 ctx.cStyleArrDec.forEach(child -> typeAst.addChild(visit(child))); 496 497 return methodDef; 498 } 499 500 @Override 501 public DetailAstImpl visitVariableDeclarators( 502 JavaLanguageParser.VariableDeclaratorsContext ctx) { 503 return flattenedTree(ctx); 504 } 505 506 @Override 507 public DetailAstImpl visitVariableDeclarator( 508 JavaLanguageParser.VariableDeclaratorContext ctx) { 509 final DetailAstImpl variableDef = createImaginary(TokenTypes.VARIABLE_DEF); 510 variableDef.addChild(createModifiers(ctx.mods)); 511 512 final DetailAstImpl type = visit(ctx.type); 513 variableDef.addChild(type); 514 variableDef.addChild(visit(ctx.id())); 515 516 // Add C style array declarator brackets to TYPE ast 517 ctx.arrayDeclarator().forEach(child -> type.addChild(visit(child))); 518 519 // If this is an assignment statement, ASSIGN becomes the parent of EXPR 520 final TerminalNode assignNode = ctx.ASSIGN(); 521 if (assignNode != null) { 522 final DetailAstImpl assign = create(assignNode); 523 variableDef.addChild(assign); 524 assign.addChild(visit(ctx.variableInitializer())); 525 } 526 return variableDef; 527 } 528 529 @Override 530 public DetailAstImpl visitVariableDeclaratorId( 531 JavaLanguageParser.VariableDeclaratorIdContext ctx) { 532 final DetailAstImpl root = new DetailAstImpl(); 533 root.addChild(createModifiers(ctx.mods)); 534 final DetailAstImpl type = visit(ctx.type); 535 root.addChild(type); 536 537 final DetailAstImpl declaratorId; 538 if (ctx.LITERAL_THIS() == null) { 539 declaratorId = visit(ctx.qualifiedName()); 540 } 541 else if (ctx.DOT() == null) { 542 declaratorId = create(ctx.LITERAL_THIS()); 543 } 544 else { 545 declaratorId = create(ctx.DOT()); 546 declaratorId.addChild(visit(ctx.qualifiedName())); 547 declaratorId.addChild(create(ctx.LITERAL_THIS())); 548 } 549 550 root.addChild(declaratorId); 551 ctx.arrayDeclarator().forEach(child -> type.addChild(visit(child))); 552 553 return root.getFirstChild(); 554 } 555 556 @Override 557 public DetailAstImpl visitArrayInitializer(JavaLanguageParser.ArrayInitializerContext ctx) { 558 final DetailAstImpl arrayInitializer = create(TokenTypes.ARRAY_INIT, ctx.start); 559 // ARRAY_INIT was child[0] 560 processChildren(arrayInitializer, ctx.children.subList(1, ctx.children.size())); 561 return arrayInitializer; 562 } 563 564 @Override 565 public DetailAstImpl visitClassOrInterfaceType( 566 JavaLanguageParser.ClassOrInterfaceTypeContext ctx) { 567 final DetailAstPair currentAST = new DetailAstPair(); 568 DetailAstPair.addAstChild(currentAST, visit(ctx.id())); 569 DetailAstPair.addAstChild(currentAST, visit(ctx.typeArguments())); 570 571 // This is how we build the annotations/ qualified name/ type parameters tree 572 for (ParserRuleContext extendedContext : ctx.extended) { 573 final DetailAstImpl dot = create(extendedContext.start); 574 DetailAstPair.makeAstRoot(currentAST, dot); 575 extendedContext.children 576 .forEach(child -> DetailAstPair.addAstChild(currentAST, visit(child))); 577 } 578 579 // Create imaginary 'TYPE' parent if specified 580 final DetailAstImpl returnTree; 581 if (ctx.createImaginaryNode) { 582 returnTree = createImaginary(TokenTypes.TYPE); 583 returnTree.addChild(currentAST.root); 584 } 585 else { 586 returnTree = currentAST.root; 587 } 588 return returnTree; 589 } 590 591 @Override 592 public DetailAstImpl visitSimpleTypeArgument( 593 JavaLanguageParser.SimpleTypeArgumentContext ctx) { 594 final DetailAstImpl typeArgument = 595 createImaginary(TokenTypes.TYPE_ARGUMENT); 596 typeArgument.addChild(visit(ctx.typeType())); 597 return typeArgument; 598 } 599 600 @Override 601 public DetailAstImpl visitWildCardTypeArgument( 602 JavaLanguageParser.WildCardTypeArgumentContext ctx) { 603 final DetailAstImpl typeArgument = createImaginary(TokenTypes.TYPE_ARGUMENT); 604 typeArgument.addChild(visit(ctx.annotations())); 605 typeArgument.addChild(create(TokenTypes.WILDCARD_TYPE, 606 (Token) ctx.QUESTION().getPayload())); 607 608 if (ctx.upperBound != null) { 609 final DetailAstImpl upperBound = create(TokenTypes.TYPE_UPPER_BOUNDS, ctx.upperBound); 610 upperBound.addChild(visit(ctx.typeType())); 611 typeArgument.addChild(upperBound); 612 } 613 else if (ctx.lowerBound != null) { 614 final DetailAstImpl lowerBound = create(TokenTypes.TYPE_LOWER_BOUNDS, ctx.lowerBound); 615 lowerBound.addChild(visit(ctx.typeType())); 616 typeArgument.addChild(lowerBound); 617 } 618 619 return typeArgument; 620 } 621 622 @Override 623 public DetailAstImpl visitQualifiedNameList(JavaLanguageParser.QualifiedNameListContext ctx) { 624 return flattenedTree(ctx); 625 } 626 627 @Override 628 public DetailAstImpl visitFormalParameters(JavaLanguageParser.FormalParametersContext ctx) { 629 final DetailAstImpl lparen = create(ctx.LPAREN()); 630 631 // We make a "PARAMETERS" node whether parameters exist or not 632 if (ctx.formalParameterList() == null) { 633 addLastSibling(lparen, createImaginary(TokenTypes.PARAMETERS)); 634 } 635 else { 636 addLastSibling(lparen, visit(ctx.formalParameterList())); 637 } 638 addLastSibling(lparen, create(ctx.RPAREN())); 639 return lparen; 640 } 641 642 @Override 643 public DetailAstImpl visitFormalParameterList( 644 JavaLanguageParser.FormalParameterListContext ctx) { 645 final DetailAstImpl parameters = createImaginary(TokenTypes.PARAMETERS); 646 processChildren(parameters, ctx.children); 647 return parameters; 648 } 649 650 @Override 651 public DetailAstImpl visitFormalParameter(JavaLanguageParser.FormalParameterContext ctx) { 652 final DetailAstImpl variableDeclaratorId = 653 visitVariableDeclaratorId(ctx.variableDeclaratorId()); 654 final DetailAstImpl parameterDef = createImaginary(TokenTypes.PARAMETER_DEF); 655 parameterDef.addChild(variableDeclaratorId); 656 return parameterDef; 657 } 658 659 @Override 660 public DetailAstImpl visitLastFormalParameter( 661 JavaLanguageParser.LastFormalParameterContext ctx) { 662 final DetailAstImpl parameterDef = 663 createImaginary(TokenTypes.PARAMETER_DEF); 664 parameterDef.addChild(visit(ctx.variableDeclaratorId())); 665 final DetailAstImpl ident = (DetailAstImpl) parameterDef.findFirstToken(TokenTypes.IDENT); 666 ident.addPreviousSibling(create(ctx.ELLIPSIS())); 667 // We attach annotations on ellipses in varargs to the 'TYPE' ast 668 final DetailAstImpl type = (DetailAstImpl) parameterDef.findFirstToken(TokenTypes.TYPE); 669 type.addChild(visit(ctx.annotations())); 670 return parameterDef; 671 } 672 673 @Override 674 public DetailAstImpl visitQualifiedName(JavaLanguageParser.QualifiedNameContext ctx) { 675 final DetailAstImpl ast = visit(ctx.id()); 676 final DetailAstPair currentAst = new DetailAstPair(); 677 DetailAstPair.addAstChild(currentAst, ast); 678 679 for (ParserRuleContext extendedContext : ctx.extended) { 680 final DetailAstImpl dot = create(extendedContext.start); 681 DetailAstPair.makeAstRoot(currentAst, dot); 682 final List<ParseTree> childList = extendedContext 683 .children.subList(1, extendedContext.children.size()); 684 processChildren(dot, childList); 685 } 686 return currentAst.getRoot(); 687 } 688 689 @Override 690 public DetailAstImpl visitLiteral(JavaLanguageParser.LiteralContext ctx) { 691 return flattenedTree(ctx); 692 } 693 694 @Override 695 public DetailAstImpl visitIntegerLiteral(JavaLanguageParser.IntegerLiteralContext ctx) { 696 final int[] longTypes = { 697 JavaLanguageLexer.DECIMAL_LITERAL_LONG, 698 JavaLanguageLexer.HEX_LITERAL_LONG, 699 JavaLanguageLexer.OCT_LITERAL_LONG, 700 JavaLanguageLexer.BINARY_LITERAL_LONG, 701 }; 702 703 final int tokenType; 704 if (TokenUtil.isOfType(ctx.start.getType(), longTypes)) { 705 tokenType = TokenTypes.NUM_LONG; 706 } 707 else { 708 tokenType = TokenTypes.NUM_INT; 709 } 710 711 return create(tokenType, ctx.start); 712 } 713 714 @Override 715 public DetailAstImpl visitFloatLiteral(JavaLanguageParser.FloatLiteralContext ctx) { 716 final DetailAstImpl floatLiteral; 717 if (TokenUtil.isOfType(ctx.start.getType(), 718 JavaLanguageLexer.DOUBLE_LITERAL, JavaLanguageLexer.HEX_DOUBLE_LITERAL)) { 719 floatLiteral = create(TokenTypes.NUM_DOUBLE, ctx.start); 720 } 721 else { 722 floatLiteral = create(TokenTypes.NUM_FLOAT, ctx.start); 723 } 724 return floatLiteral; 725 } 726 727 @Override 728 public DetailAstImpl visitTextBlockLiteral(JavaLanguageParser.TextBlockLiteralContext ctx) { 729 final DetailAstImpl textBlockLiteralBegin = create(ctx.TEXT_BLOCK_LITERAL_BEGIN()); 730 textBlockLiteralBegin.addChild(create(ctx.TEXT_BLOCK_CONTENT())); 731 textBlockLiteralBegin.addChild(create(ctx.TEXT_BLOCK_LITERAL_END())); 732 return textBlockLiteralBegin; 733 } 734 735 @Override 736 public DetailAstImpl visitAnnotations(JavaLanguageParser.AnnotationsContext ctx) { 737 final DetailAstImpl annotations; 738 739 if (!ctx.createImaginaryNode && ctx.anno.isEmpty()) { 740 // There are no annotations, and we don't want to create the empty node 741 annotations = null; 742 } 743 else { 744 // There are annotations, or we just want the empty node 745 annotations = createImaginary(TokenTypes.ANNOTATIONS); 746 processChildren(annotations, ctx.anno); 747 } 748 749 return annotations; 750 } 751 752 @Override 753 public DetailAstImpl visitAnnotation(JavaLanguageParser.AnnotationContext ctx) { 754 final DetailAstImpl annotation = createImaginary(TokenTypes.ANNOTATION); 755 processChildren(annotation, ctx.children); 756 return annotation; 757 } 758 759 @Override 760 public DetailAstImpl visitElementValuePairs(JavaLanguageParser.ElementValuePairsContext ctx) { 761 return flattenedTree(ctx); 762 } 763 764 @Override 765 public DetailAstImpl visitElementValuePair(JavaLanguageParser.ElementValuePairContext ctx) { 766 final DetailAstImpl elementValuePair = 767 createImaginary(TokenTypes.ANNOTATION_MEMBER_VALUE_PAIR); 768 processChildren(elementValuePair, ctx.children); 769 return elementValuePair; 770 } 771 772 @Override 773 public DetailAstImpl visitElementValue(JavaLanguageParser.ElementValueContext ctx) { 774 return flattenedTree(ctx); 775 } 776 777 @Override 778 public DetailAstImpl visitElementValueArrayInitializer( 779 JavaLanguageParser.ElementValueArrayInitializerContext ctx) { 780 final DetailAstImpl arrayInit = 781 create(TokenTypes.ANNOTATION_ARRAY_INIT, (Token) ctx.LCURLY().getPayload()); 782 processChildren(arrayInit, ctx.children.subList(1, ctx.children.size())); 783 return arrayInit; 784 } 785 786 @Override 787 public DetailAstImpl visitAnnotationTypeDeclaration( 788 JavaLanguageParser.AnnotationTypeDeclarationContext ctx) { 789 return createTypeDeclaration(ctx, TokenTypes.ANNOTATION_DEF, ctx.mods); 790 } 791 792 @Override 793 public DetailAstImpl visitAnnotationTypeBody( 794 JavaLanguageParser.AnnotationTypeBodyContext ctx) { 795 final DetailAstImpl objBlock = createImaginary(TokenTypes.OBJBLOCK); 796 processChildren(objBlock, ctx.children); 797 return objBlock; 798 } 799 800 @Override 801 public DetailAstImpl visitAnnotationTypeElementDeclaration( 802 JavaLanguageParser.AnnotationTypeElementDeclarationContext ctx) { 803 final DetailAstImpl returnTree; 804 if (ctx.SEMI() == null) { 805 returnTree = visit(ctx.annotationTypeElementRest()); 806 } 807 else { 808 returnTree = create(ctx.SEMI()); 809 } 810 return returnTree; 811 } 812 813 @Override 814 public DetailAstImpl visitAnnotationField(JavaLanguageParser.AnnotationFieldContext ctx) { 815 final DetailAstImpl dummyNode = new DetailAstImpl(); 816 // Since the TYPE AST is built by visitAnnotationMethodOrConstantRest(), we skip it 817 // here (child [0]) 818 processChildren(dummyNode, Collections.singletonList(ctx.children.get(1))); 819 // We also append the SEMI token to the first child [size() - 1], 820 // until https://github.com/checkstyle/checkstyle/issues/3151 821 dummyNode.getFirstChild().addChild(create(ctx.SEMI())); 822 return dummyNode.getFirstChild(); 823 } 824 825 @Override 826 public DetailAstImpl visitAnnotationType(JavaLanguageParser.AnnotationTypeContext ctx) { 827 return flattenedTree(ctx); 828 } 829 830 @Override 831 public DetailAstImpl visitAnnotationMethodRest( 832 JavaLanguageParser.AnnotationMethodRestContext ctx) { 833 final DetailAstImpl annotationFieldDef = 834 createImaginary(TokenTypes.ANNOTATION_FIELD_DEF); 835 annotationFieldDef.addChild(createModifiers(ctx.mods)); 836 annotationFieldDef.addChild(visit(ctx.type)); 837 838 // Process all children except C style array declarators 839 processChildren(annotationFieldDef, ctx.children.stream() 840 .filter(child -> !(child instanceof JavaLanguageParser.ArrayDeclaratorContext)) 841 .collect(Collectors.toUnmodifiableList())); 842 843 // We add C style array declarator brackets to TYPE ast 844 final DetailAstImpl typeAst = 845 (DetailAstImpl) annotationFieldDef.findFirstToken(TokenTypes.TYPE); 846 ctx.cStyleArrDec.forEach(child -> typeAst.addChild(visit(child))); 847 848 return annotationFieldDef; 849 } 850 851 @Override 852 public DetailAstImpl visitDefaultValue(JavaLanguageParser.DefaultValueContext ctx) { 853 final DetailAstImpl defaultValue = create(ctx.LITERAL_DEFAULT()); 854 defaultValue.addChild(visit(ctx.elementValue())); 855 return defaultValue; 856 } 857 858 @Override 859 public DetailAstImpl visitConstructorBlock(JavaLanguageParser.ConstructorBlockContext ctx) { 860 final DetailAstImpl slist = create(TokenTypes.SLIST, ctx.start); 861 // SLIST was child [0] 862 processChildren(slist, ctx.children.subList(1, ctx.children.size())); 863 return slist; 864 } 865 866 @Override 867 public DetailAstImpl visitExplicitCtorCall(JavaLanguageParser.ExplicitCtorCallContext ctx) { 868 final DetailAstImpl root; 869 if (ctx.LITERAL_THIS() == null) { 870 root = create(TokenTypes.SUPER_CTOR_CALL, (Token) ctx.LITERAL_SUPER().getPayload()); 871 } 872 else { 873 root = create(TokenTypes.CTOR_CALL, (Token) ctx.LITERAL_THIS().getPayload()); 874 } 875 root.addChild(visit(ctx.typeArguments())); 876 root.addChild(visit(ctx.arguments())); 877 root.addChild(create(ctx.SEMI())); 878 return root; 879 } 880 881 @Override 882 public DetailAstImpl visitPrimaryCtorCall(JavaLanguageParser.PrimaryCtorCallContext ctx) { 883 final DetailAstImpl primaryCtorCall = create(TokenTypes.SUPER_CTOR_CALL, 884 (Token) ctx.LITERAL_SUPER().getPayload()); 885 // filter 'LITERAL_SUPER' 886 processChildren(primaryCtorCall, ctx.children.stream() 887 .filter(child -> !child.equals(ctx.LITERAL_SUPER())) 888 .collect(Collectors.toUnmodifiableList())); 889 return primaryCtorCall; 890 } 891 892 @Override 893 public DetailAstImpl visitBlock(JavaLanguageParser.BlockContext ctx) { 894 final DetailAstImpl slist = create(TokenTypes.SLIST, ctx.start); 895 // SLIST was child [0] 896 processChildren(slist, ctx.children.subList(1, ctx.children.size())); 897 return slist; 898 } 899 900 @Override 901 public DetailAstImpl visitLocalVar(JavaLanguageParser.LocalVarContext ctx) { 902 return flattenedTree(ctx); 903 } 904 905 @Override 906 public DetailAstImpl visitBlockStat(JavaLanguageParser.BlockStatContext ctx) { 907 return flattenedTree(ctx); 908 } 909 910 @Override 911 public DetailAstImpl visitAssertExp(JavaLanguageParser.AssertExpContext ctx) { 912 final DetailAstImpl assertExp = create(ctx.ASSERT()); 913 // child[0] is 'ASSERT' 914 processChildren(assertExp, ctx.children.subList(1, ctx.children.size())); 915 return assertExp; 916 } 917 918 @Override 919 public DetailAstImpl visitIfStat(JavaLanguageParser.IfStatContext ctx) { 920 final DetailAstImpl ifStat = create(ctx.LITERAL_IF()); 921 // child[0] is 'LITERAL_IF' 922 processChildren(ifStat, ctx.children.subList(1, ctx.children.size())); 923 return ifStat; 924 } 925 926 @Override 927 public DetailAstImpl visitForStat(JavaLanguageParser.ForStatContext ctx) { 928 final DetailAstImpl forInit = create(ctx.start); 929 // child[0] is LITERAL_FOR 930 processChildren(forInit, ctx.children.subList(1, ctx.children.size())); 931 return forInit; 932 } 933 934 @Override 935 public DetailAstImpl visitWhileStat(JavaLanguageParser.WhileStatContext ctx) { 936 final DetailAstImpl whileStatement = create(ctx.start); 937 // 'LITERAL_WHILE' is child[0] 938 processChildren(whileStatement, ctx.children.subList(1, ctx.children.size())); 939 return whileStatement; 940 } 941 942 @Override 943 public DetailAstImpl visitDoStat(JavaLanguageParser.DoStatContext ctx) { 944 final DetailAstImpl doStatement = create(ctx.start); 945 // 'LITERAL_DO' is child[0] 946 doStatement.addChild(visit(ctx.statement())); 947 // We make 'LITERAL_WHILE' into 'DO_WHILE' 948 doStatement.addChild(create(TokenTypes.DO_WHILE, (Token) ctx.LITERAL_WHILE().getPayload())); 949 doStatement.addChild(visit(ctx.parExpression())); 950 doStatement.addChild(create(ctx.SEMI())); 951 return doStatement; 952 } 953 954 @Override 955 public DetailAstImpl visitTryStat(JavaLanguageParser.TryStatContext ctx) { 956 final DetailAstImpl tryStat = create(ctx.start); 957 // child[0] is 'LITERAL_TRY' 958 processChildren(tryStat, ctx.children.subList(1, ctx.children.size())); 959 return tryStat; 960 } 961 962 @Override 963 public DetailAstImpl visitTryWithResourceStat( 964 JavaLanguageParser.TryWithResourceStatContext ctx) { 965 final DetailAstImpl tryWithResources = create(ctx.LITERAL_TRY()); 966 // child[0] is 'LITERAL_TRY' 967 processChildren(tryWithResources, ctx.children.subList(1, ctx.children.size())); 968 return tryWithResources; 969 } 970 971 @Override 972 public DetailAstImpl visitYieldStat(JavaLanguageParser.YieldStatContext ctx) { 973 final DetailAstImpl yieldParent = create(ctx.LITERAL_YIELD()); 974 // LITERAL_YIELD is child[0] 975 processChildren(yieldParent, ctx.children.subList(1, ctx.children.size())); 976 return yieldParent; 977 } 978 979 @Override 980 public DetailAstImpl visitSyncStat(JavaLanguageParser.SyncStatContext ctx) { 981 final DetailAstImpl syncStatement = create(ctx.start); 982 // child[0] is 'LITERAL_SYNCHRONIZED' 983 processChildren(syncStatement, ctx.children.subList(1, ctx.children.size())); 984 return syncStatement; 985 } 986 987 @Override 988 public DetailAstImpl visitReturnStat(JavaLanguageParser.ReturnStatContext ctx) { 989 final DetailAstImpl returnStat = create(ctx.LITERAL_RETURN()); 990 // child[0] is 'LITERAL_RETURN' 991 processChildren(returnStat, ctx.children.subList(1, ctx.children.size())); 992 return returnStat; 993 } 994 995 @Override 996 public DetailAstImpl visitThrowStat(JavaLanguageParser.ThrowStatContext ctx) { 997 final DetailAstImpl throwStat = create(ctx.LITERAL_THROW()); 998 // child[0] is 'LITERAL_THROW' 999 processChildren(throwStat, ctx.children.subList(1, ctx.children.size())); 1000 return throwStat; 1001 } 1002 1003 @Override 1004 public DetailAstImpl visitBreakStat(JavaLanguageParser.BreakStatContext ctx) { 1005 final DetailAstImpl literalBreak = create(ctx.LITERAL_BREAK()); 1006 // child[0] is 'LITERAL_BREAK' 1007 processChildren(literalBreak, ctx.children.subList(1, ctx.children.size())); 1008 return literalBreak; 1009 } 1010 1011 @Override 1012 public DetailAstImpl visitContinueStat(JavaLanguageParser.ContinueStatContext ctx) { 1013 final DetailAstImpl continueStat = create(ctx.LITERAL_CONTINUE()); 1014 // child[0] is 'LITERAL_CONTINUE' 1015 processChildren(continueStat, ctx.children.subList(1, ctx.children.size())); 1016 return continueStat; 1017 } 1018 1019 @Override 1020 public DetailAstImpl visitEmptyStat(JavaLanguageParser.EmptyStatContext ctx) { 1021 return create(TokenTypes.EMPTY_STAT, ctx.start); 1022 } 1023 1024 @Override 1025 public DetailAstImpl visitExpStat(JavaLanguageParser.ExpStatContext ctx) { 1026 final DetailAstImpl expStatRoot = visit(ctx.statementExpression); 1027 addLastSibling(expStatRoot, create(ctx.SEMI())); 1028 return expStatRoot; 1029 } 1030 1031 @Override 1032 public DetailAstImpl visitLabelStat(JavaLanguageParser.LabelStatContext ctx) { 1033 final DetailAstImpl labelStat = create(TokenTypes.LABELED_STAT, 1034 (Token) ctx.COLON().getPayload()); 1035 labelStat.addChild(visit(ctx.id())); 1036 labelStat.addChild(visit(ctx.statement())); 1037 return labelStat; 1038 } 1039 1040 @Override 1041 public DetailAstImpl visitSwitchExpressionOrStatement( 1042 JavaLanguageParser.SwitchExpressionOrStatementContext ctx) { 1043 final DetailAstImpl switchStat = create(ctx.LITERAL_SWITCH()); 1044 switchStat.addChild(visit(ctx.parExpression())); 1045 switchStat.addChild(create(ctx.LCURLY())); 1046 switchStat.addChild(visit(ctx.switchBlock())); 1047 switchStat.addChild(create(ctx.RCURLY())); 1048 return switchStat; 1049 } 1050 1051 @Override 1052 public DetailAstImpl visitSwitchRules(JavaLanguageParser.SwitchRulesContext ctx) { 1053 final DetailAstImpl dummyRoot = new DetailAstImpl(); 1054 ctx.switchLabeledRule().forEach(switchLabeledRuleContext -> { 1055 final DetailAstImpl switchRule = visit(switchLabeledRuleContext); 1056 final DetailAstImpl switchRuleParent = createImaginary(TokenTypes.SWITCH_RULE); 1057 switchRuleParent.addChild(switchRule); 1058 dummyRoot.addChild(switchRuleParent); 1059 }); 1060 return dummyRoot.getFirstChild(); 1061 } 1062 1063 @Override 1064 public DetailAstImpl visitSwitchBlocks(JavaLanguageParser.SwitchBlocksContext ctx) { 1065 final DetailAstImpl dummyRoot = new DetailAstImpl(); 1066 ctx.groups.forEach(group -> dummyRoot.addChild(visit(group))); 1067 1068 // Add any empty switch labels to end of statement in one 'CASE_GROUP' 1069 if (!ctx.emptyLabels.isEmpty()) { 1070 final DetailAstImpl emptyLabelParent = 1071 createImaginary(TokenTypes.CASE_GROUP); 1072 ctx.emptyLabels.forEach(label -> emptyLabelParent.addChild(visit(label))); 1073 dummyRoot.addChild(emptyLabelParent); 1074 } 1075 return dummyRoot.getFirstChild(); 1076 } 1077 1078 @Override 1079 public DetailAstImpl visitSwitchLabeledExpression( 1080 JavaLanguageParser.SwitchLabeledExpressionContext ctx) { 1081 return flattenedTree(ctx); 1082 } 1083 1084 @Override 1085 public DetailAstImpl visitSwitchLabeledBlock( 1086 JavaLanguageParser.SwitchLabeledBlockContext ctx) { 1087 return flattenedTree(ctx); 1088 } 1089 1090 @Override 1091 public DetailAstImpl visitSwitchLabeledThrow( 1092 JavaLanguageParser.SwitchLabeledThrowContext ctx) { 1093 final DetailAstImpl switchLabel = visit(ctx.switchLabel()); 1094 addLastSibling(switchLabel, create(ctx.LAMBDA())); 1095 final DetailAstImpl literalThrow = create(ctx.LITERAL_THROW()); 1096 literalThrow.addChild(visit(ctx.expression())); 1097 literalThrow.addChild(create(ctx.SEMI())); 1098 addLastSibling(switchLabel, literalThrow); 1099 return switchLabel; 1100 } 1101 1102 @Override 1103 public DetailAstImpl visitElseStat(JavaLanguageParser.ElseStatContext ctx) { 1104 final DetailAstImpl elseStat = create(ctx.LITERAL_ELSE()); 1105 // child[0] is 'LITERAL_ELSE' 1106 processChildren(elseStat, ctx.children.subList(1, ctx.children.size())); 1107 return elseStat; 1108 } 1109 1110 @Override 1111 public DetailAstImpl visitCatchClause(JavaLanguageParser.CatchClauseContext ctx) { 1112 final DetailAstImpl catchClause = create(TokenTypes.LITERAL_CATCH, 1113 (Token) ctx.LITERAL_CATCH().getPayload()); 1114 // 'LITERAL_CATCH' is child[0] 1115 processChildren(catchClause, ctx.children.subList(1, ctx.children.size())); 1116 return catchClause; 1117 } 1118 1119 @Override 1120 public DetailAstImpl visitCatchParameter(JavaLanguageParser.CatchParameterContext ctx) { 1121 final DetailAstImpl catchParameterDef = createImaginary(TokenTypes.PARAMETER_DEF); 1122 catchParameterDef.addChild(createModifiers(ctx.mods)); 1123 // filter mods 1124 processChildren(catchParameterDef, ctx.children.stream() 1125 .filter(child -> !(child instanceof JavaLanguageParser.VariableModifierContext)) 1126 .collect(Collectors.toUnmodifiableList())); 1127 return catchParameterDef; 1128 } 1129 1130 @Override 1131 public DetailAstImpl visitCatchType(JavaLanguageParser.CatchTypeContext ctx) { 1132 final DetailAstImpl type = createImaginary(TokenTypes.TYPE); 1133 processChildren(type, ctx.children); 1134 return type; 1135 } 1136 1137 @Override 1138 public DetailAstImpl visitFinallyBlock(JavaLanguageParser.FinallyBlockContext ctx) { 1139 final DetailAstImpl finallyBlock = create(ctx.LITERAL_FINALLY()); 1140 // child[0] is 'LITERAL_FINALLY' 1141 processChildren(finallyBlock, ctx.children.subList(1, ctx.children.size())); 1142 return finallyBlock; 1143 } 1144 1145 @Override 1146 public DetailAstImpl visitResourceSpecification( 1147 JavaLanguageParser.ResourceSpecificationContext ctx) { 1148 final DetailAstImpl resourceSpecification = 1149 createImaginary(TokenTypes.RESOURCE_SPECIFICATION); 1150 processChildren(resourceSpecification, ctx.children); 1151 return resourceSpecification; 1152 } 1153 1154 @Override 1155 public DetailAstImpl visitResources(JavaLanguageParser.ResourcesContext ctx) { 1156 final DetailAstImpl firstResource = visit(ctx.resource(0)); 1157 final DetailAstImpl resources = createImaginary(TokenTypes.RESOURCES); 1158 resources.addChild(firstResource); 1159 processChildren(resources, ctx.children.subList(1, ctx.children.size())); 1160 return resources; 1161 } 1162 1163 @Override 1164 public DetailAstImpl visitResourceDeclaration( 1165 JavaLanguageParser.ResourceDeclarationContext ctx) { 1166 final DetailAstImpl resource = createImaginary(TokenTypes.RESOURCE); 1167 resource.addChild(visit(ctx.variableDeclaratorId())); 1168 1169 final DetailAstImpl assign = create(ctx.ASSIGN()); 1170 resource.addChild(assign); 1171 assign.addChild(visit(ctx.expression())); 1172 return resource; 1173 } 1174 1175 @Override 1176 public DetailAstImpl visitVariableAccess(JavaLanguageParser.VariableAccessContext ctx) { 1177 final DetailAstImpl resource; 1178 if (ctx.accessList.isEmpty()) { 1179 resource = createImaginary(TokenTypes.RESOURCE); 1180 resource.addChild(visit(ctx.id())); 1181 } 1182 else { 1183 final DetailAstPair currentAst = new DetailAstPair(); 1184 ctx.accessList.forEach(fieldAccess -> { 1185 DetailAstPair.addAstChild(currentAst, visit(fieldAccess.expr())); 1186 DetailAstPair.makeAstRoot(currentAst, create(fieldAccess.DOT())); 1187 }); 1188 resource = createImaginary(TokenTypes.RESOURCE); 1189 resource.addChild(currentAst.root); 1190 if (ctx.LITERAL_THIS() == null) { 1191 resource.getFirstChild().addChild(visit(ctx.id())); 1192 } 1193 else { 1194 resource.getFirstChild().addChild(create(ctx.LITERAL_THIS())); 1195 } 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 visitTemplateExp(JavaLanguageParser.TemplateExpContext ctx) { 1542 final DetailAstImpl dot = create(ctx.DOT()); 1543 dot.addChild(visit(ctx.expr())); 1544 dot.addChild(visit(ctx.templateArgument())); 1545 return dot; 1546 } 1547 1548 @Override 1549 public DetailAstImpl visitPostfix(JavaLanguageParser.PostfixContext ctx) { 1550 final DetailAstImpl postfix; 1551 if (ctx.postfix.getType() == JavaLanguageLexer.INC) { 1552 postfix = create(TokenTypes.POST_INC, ctx.postfix); 1553 } 1554 else { 1555 postfix = create(TokenTypes.POST_DEC, ctx.postfix); 1556 } 1557 postfix.addChild(visit(ctx.expr())); 1558 return postfix; 1559 } 1560 1561 @Override 1562 public DetailAstImpl visitMethodRef(JavaLanguageParser.MethodRefContext ctx) { 1563 final DetailAstImpl doubleColon = create(TokenTypes.METHOD_REF, 1564 (Token) ctx.DOUBLE_COLON().getPayload()); 1565 final List<ParseTree> children = ctx.children.stream() 1566 .filter(child -> !child.equals(ctx.DOUBLE_COLON())) 1567 .collect(Collectors.toUnmodifiableList()); 1568 processChildren(doubleColon, children); 1569 return doubleColon; 1570 } 1571 1572 @Override 1573 public DetailAstImpl visitTernaryOp(JavaLanguageParser.TernaryOpContext ctx) { 1574 final DetailAstImpl root = create(ctx.QUESTION()); 1575 processChildren(root, ctx.children.stream() 1576 .filter(child -> !child.equals(ctx.QUESTION())) 1577 .collect(Collectors.toUnmodifiableList())); 1578 return root; 1579 } 1580 1581 @Override 1582 public DetailAstImpl visitBinOp(JavaLanguageParser.BinOpContext ctx) { 1583 final DetailAstImpl bop = create(ctx.bop); 1584 1585 // To improve performance, we iterate through binary operations 1586 // since they are frequently deeply nested. 1587 final List<JavaLanguageParser.BinOpContext> binOpList = new ArrayList<>(); 1588 ParseTree firstExpression = ctx.expr(0); 1589 while (firstExpression instanceof JavaLanguageParser.BinOpContext) { 1590 // Get all nested binOps 1591 binOpList.add((JavaLanguageParser.BinOpContext) firstExpression); 1592 firstExpression = ((JavaLanguageParser.BinOpContext) firstExpression).expr(0); 1593 } 1594 1595 if (binOpList.isEmpty()) { 1596 final DetailAstImpl leftChild = visit(ctx.children.get(0)); 1597 bop.addChild(leftChild); 1598 } 1599 else { 1600 // Map all descendants to individual AST's since we can parallelize this 1601 // operation 1602 final Queue<DetailAstImpl> descendantList = binOpList.parallelStream() 1603 .map(this::getInnerBopAst) 1604 .collect(Collectors.toCollection(ConcurrentLinkedQueue::new)); 1605 1606 bop.addChild(descendantList.poll()); 1607 DetailAstImpl pointer = bop.getFirstChild(); 1608 // Build tree 1609 for (DetailAstImpl descendant : descendantList) { 1610 pointer.getFirstChild().addPreviousSibling(descendant); 1611 pointer = descendant; 1612 } 1613 } 1614 1615 bop.addChild(visit(ctx.children.get(2))); 1616 return bop; 1617 } 1618 1619 /** 1620 * Builds the binary operation (binOp) AST. 1621 * 1622 * @param descendant the BinOpContext to build AST from 1623 * @return binOp AST 1624 */ 1625 private DetailAstImpl getInnerBopAst(JavaLanguageParser.BinOpContext descendant) { 1626 final DetailAstImpl innerBop = create(descendant.bop); 1627 final JavaLanguageParser.ExprContext expr = descendant.expr(0); 1628 if (!(expr instanceof JavaLanguageParser.BinOpContext)) { 1629 innerBop.addChild(visit(expr)); 1630 } 1631 innerBop.addChild(visit(descendant.expr(1))); 1632 return innerBop; 1633 } 1634 1635 @Override 1636 public DetailAstImpl visitMethodCall(JavaLanguageParser.MethodCallContext ctx) { 1637 final DetailAstImpl methodCall = create(TokenTypes.METHOD_CALL, 1638 (Token) ctx.LPAREN().getPayload()); 1639 // We always add an 'ELIST' node 1640 final DetailAstImpl expressionList = Optional.ofNullable(visit(ctx.expressionList())) 1641 .orElseGet(() -> createImaginary(TokenTypes.ELIST)); 1642 1643 final DetailAstImpl dot = create(ctx.DOT()); 1644 dot.addChild(visit(ctx.expr())); 1645 dot.addChild(visit(ctx.id())); 1646 methodCall.addChild(dot); 1647 methodCall.addChild(expressionList); 1648 methodCall.addChild(create((Token) ctx.RPAREN().getPayload())); 1649 return methodCall; 1650 } 1651 1652 @Override 1653 public DetailAstImpl visitTypeCastParameters( 1654 JavaLanguageParser.TypeCastParametersContext ctx) { 1655 final DetailAstImpl typeType = visit(ctx.typeType(0)); 1656 for (int i = 0; i < ctx.BAND().size(); i++) { 1657 addLastSibling(typeType, create(TokenTypes.TYPE_EXTENSION_AND, 1658 (Token) ctx.BAND(i).getPayload())); 1659 addLastSibling(typeType, visit(ctx.typeType(i + 1))); 1660 } 1661 return typeType; 1662 } 1663 1664 @Override 1665 public DetailAstImpl visitSingleLambdaParam(JavaLanguageParser.SingleLambdaParamContext ctx) { 1666 return flattenedTree(ctx); 1667 } 1668 1669 @Override 1670 public DetailAstImpl visitFormalLambdaParam(JavaLanguageParser.FormalLambdaParamContext ctx) { 1671 final DetailAstImpl lparen = create(ctx.LPAREN()); 1672 1673 // We add an 'PARAMETERS' node here whether it exists or not 1674 final DetailAstImpl parameters = Optional.ofNullable(visit(ctx.formalParameterList())) 1675 .orElseGet(() -> createImaginary(TokenTypes.PARAMETERS)); 1676 addLastSibling(lparen, parameters); 1677 addLastSibling(lparen, create(ctx.RPAREN())); 1678 return lparen; 1679 } 1680 1681 @Override 1682 public DetailAstImpl visitMultiLambdaParam(JavaLanguageParser.MultiLambdaParamContext ctx) { 1683 final DetailAstImpl lparen = create(ctx.LPAREN()); 1684 addLastSibling(lparen, visit(ctx.multiLambdaParams())); 1685 addLastSibling(lparen, create(ctx.RPAREN())); 1686 return lparen; 1687 } 1688 1689 @Override 1690 public DetailAstImpl visitMultiLambdaParams(JavaLanguageParser.MultiLambdaParamsContext ctx) { 1691 final DetailAstImpl parameters = createImaginary(TokenTypes.PARAMETERS); 1692 parameters.addChild(createLambdaParameter(ctx.id(0))); 1693 1694 for (int i = 0; i < ctx.COMMA().size(); i++) { 1695 parameters.addChild(create(ctx.COMMA(i))); 1696 parameters.addChild(createLambdaParameter(ctx.id(i + 1))); 1697 } 1698 return parameters; 1699 } 1700 1701 /** 1702 * Creates a 'PARAMETER_DEF' node for a lambda expression, with 1703 * imaginary modifier and type nodes. 1704 * 1705 * @param ctx the IdContext to create imaginary nodes for 1706 * @return DetailAstImpl of lambda parameter 1707 */ 1708 private DetailAstImpl createLambdaParameter(JavaLanguageParser.IdContext ctx) { 1709 final DetailAstImpl ident = visitId(ctx); 1710 final DetailAstImpl parameter = createImaginary(TokenTypes.PARAMETER_DEF); 1711 final DetailAstImpl modifiers = createImaginary(TokenTypes.MODIFIERS); 1712 final DetailAstImpl type = createImaginary(TokenTypes.TYPE); 1713 parameter.addChild(modifiers); 1714 parameter.addChild(type); 1715 parameter.addChild(ident); 1716 return parameter; 1717 } 1718 1719 @Override 1720 public DetailAstImpl visitParenPrimary(JavaLanguageParser.ParenPrimaryContext ctx) { 1721 return flattenedTree(ctx); 1722 } 1723 1724 @Override 1725 public DetailAstImpl visitTokenPrimary(JavaLanguageParser.TokenPrimaryContext ctx) { 1726 return flattenedTree(ctx); 1727 } 1728 1729 @Override 1730 public DetailAstImpl visitClassRefPrimary(JavaLanguageParser.ClassRefPrimaryContext ctx) { 1731 final DetailAstImpl dot = create(ctx.DOT()); 1732 final DetailAstImpl primaryTypeNoArray = visit(ctx.type); 1733 dot.addChild(primaryTypeNoArray); 1734 if (TokenUtil.isOfType(primaryTypeNoArray, TokenTypes.DOT)) { 1735 // We append '[]' to the qualified name 'TYPE' `ast 1736 ctx.arrayDeclarator() 1737 .forEach(child -> primaryTypeNoArray.addChild(visit(child))); 1738 } 1739 else { 1740 ctx.arrayDeclarator() 1741 .forEach(child -> addLastSibling(primaryTypeNoArray, visit(child))); 1742 } 1743 dot.addChild(create(ctx.LITERAL_CLASS())); 1744 return dot; 1745 } 1746 1747 @Override 1748 public DetailAstImpl visitPrimitivePrimary(JavaLanguageParser.PrimitivePrimaryContext ctx) { 1749 final DetailAstImpl dot = create(ctx.DOT()); 1750 final DetailAstImpl primaryTypeNoArray = visit(ctx.type); 1751 dot.addChild(primaryTypeNoArray); 1752 ctx.arrayDeclarator().forEach(child -> dot.addChild(visit(child))); 1753 dot.addChild(create(ctx.LITERAL_CLASS())); 1754 return dot; 1755 } 1756 1757 @Override 1758 public DetailAstImpl visitTemplateArgument(JavaLanguageParser.TemplateArgumentContext ctx) { 1759 return Objects.requireNonNullElseGet(visit(ctx.template()), 1760 () -> buildSimpleStringTemplateArgument(ctx)); 1761 } 1762 1763 /** 1764 * Builds a simple string template argument AST, which basically means that we 1765 * transform a string literal into a string template AST because it is a 1766 * string template argument. 1767 * 1768 * @param ctx the TemplateArgumentContext to build AST from 1769 * @return DetailAstImpl of string template argument 1770 */ 1771 private static DetailAstImpl buildSimpleStringTemplateArgument( 1772 JavaLanguageParser.TemplateArgumentContext ctx) { 1773 final int startColumn = ctx.start.getCharPositionInLine(); 1774 final int endColumn = startColumn + ctx.getText().length() - 1; 1775 final int lineNumber = ctx.start.getLine(); 1776 1777 final DetailAstImpl templateArgument = createImaginary( 1778 TokenTypes.STRING_TEMPLATE_BEGIN, QUOTE, 1779 lineNumber, startColumn 1780 ); 1781 1782 final int quoteLength = QUOTE.length(); 1783 final int tokenTextLength = ctx.getText().length(); 1784 1785 final String actualContent = ctx.getText() 1786 .substring(quoteLength, tokenTextLength - quoteLength); 1787 1788 final DetailAstImpl content = createImaginary( 1789 TokenTypes.STRING_TEMPLATE_CONTENT, actualContent, 1790 lineNumber, startColumn + quoteLength 1791 ); 1792 templateArgument.addChild(content); 1793 1794 final DetailAstImpl end = createImaginary( 1795 TokenTypes.STRING_TEMPLATE_END, QUOTE, 1796 lineNumber, endColumn 1797 ); 1798 templateArgument.addChild(end); 1799 1800 return templateArgument; 1801 } 1802 1803 @Override 1804 public DetailAstImpl visitStringTemplate(JavaLanguageParser.StringTemplateContext ctx) { 1805 final DetailAstImpl stringTemplateBegin = visit(ctx.stringTemplateBegin()); 1806 1807 final Optional<DetailAstImpl> expression = Optional.ofNullable(ctx.expr()) 1808 .map(this::visit); 1809 1810 if (expression.isPresent()) { 1811 final DetailAstImpl imaginaryExpression = 1812 createImaginary(TokenTypes.EMBEDDED_EXPRESSION); 1813 imaginaryExpression.addChild(expression.orElseThrow()); 1814 stringTemplateBegin.addChild(imaginaryExpression); 1815 } 1816 1817 ctx.stringTemplateMiddle().stream() 1818 .map(this::buildStringTemplateMiddle) 1819 .forEach(stringTemplateBegin::addChild); 1820 1821 final DetailAstImpl stringTemplateEnd = visit(ctx.stringTemplateEnd()); 1822 stringTemplateBegin.addChild(stringTemplateEnd); 1823 return stringTemplateBegin; 1824 } 1825 1826 /** 1827 * Builds a string template middle AST. 1828 * 1829 * @param ctx the StringTemplateMiddleContext to build AST from 1830 * @return DetailAstImpl of string template middle 1831 */ 1832 private DetailAstImpl buildStringTemplateMiddle( 1833 JavaLanguageParser.StringTemplateMiddleContext ctx) { 1834 final DetailAstImpl stringTemplateMiddle = 1835 visit(ctx.stringTemplateMid()); 1836 1837 final Optional<DetailAstImpl> expression = Optional.ofNullable(ctx.expr()) 1838 .map(this::visit); 1839 1840 if (expression.isPresent()) { 1841 final DetailAstImpl imaginaryExpression = 1842 createImaginary(TokenTypes.EMBEDDED_EXPRESSION); 1843 imaginaryExpression.addChild(expression.orElseThrow()); 1844 addLastSibling(stringTemplateMiddle, imaginaryExpression); 1845 } 1846 1847 return stringTemplateMiddle; 1848 } 1849 1850 @Override 1851 public DetailAstImpl visitStringTemplateBegin( 1852 JavaLanguageParser.StringTemplateBeginContext ctx) { 1853 final DetailAstImpl stringTemplateBegin = 1854 create(ctx.STRING_TEMPLATE_BEGIN()); 1855 final Optional<DetailAstImpl> stringTemplateContent = 1856 Optional.ofNullable(ctx.STRING_TEMPLATE_CONTENT()) 1857 .map(this::create); 1858 stringTemplateContent.ifPresent(stringTemplateBegin::addChild); 1859 final DetailAstImpl embeddedExpressionBegin = create(ctx.EMBEDDED_EXPRESSION_BEGIN()); 1860 stringTemplateBegin.addChild(embeddedExpressionBegin); 1861 return stringTemplateBegin; 1862 } 1863 1864 @Override 1865 public DetailAstImpl visitStringTemplateMid(JavaLanguageParser.StringTemplateMidContext ctx) { 1866 final DetailAstImpl embeddedExpressionEnd = create(ctx.EMBEDDED_EXPRESSION_END()); 1867 final Optional<DetailAstImpl> stringTemplateContent = 1868 Optional.ofNullable(ctx.STRING_TEMPLATE_CONTENT()) 1869 .map(this::create); 1870 stringTemplateContent.ifPresent(self -> addLastSibling(embeddedExpressionEnd, self)); 1871 final DetailAstImpl embeddedExpressionBegin = create(ctx.EMBEDDED_EXPRESSION_BEGIN()); 1872 addLastSibling(embeddedExpressionEnd, embeddedExpressionBegin); 1873 return embeddedExpressionEnd; 1874 } 1875 1876 @Override 1877 public DetailAstImpl visitStringTemplateEnd(JavaLanguageParser.StringTemplateEndContext ctx) { 1878 final DetailAstImpl embeddedExpressionEnd = create(ctx.EMBEDDED_EXPRESSION_END()); 1879 final Optional<DetailAstImpl> stringTemplateContent = 1880 Optional.ofNullable(ctx.STRING_TEMPLATE_CONTENT()) 1881 .map(this::create); 1882 stringTemplateContent.ifPresent(self -> addLastSibling(embeddedExpressionEnd, self)); 1883 final DetailAstImpl stringTemplateEnd = create(ctx.STRING_TEMPLATE_END()); 1884 addLastSibling(embeddedExpressionEnd, stringTemplateEnd); 1885 return embeddedExpressionEnd; 1886 } 1887 1888 @Override 1889 public DetailAstImpl visitCreator(JavaLanguageParser.CreatorContext ctx) { 1890 return flattenedTree(ctx); 1891 } 1892 1893 @Override 1894 public DetailAstImpl visitCreatedNameObject(JavaLanguageParser.CreatedNameObjectContext ctx) { 1895 final DetailAstPair currentAST = new DetailAstPair(); 1896 DetailAstPair.addAstChild(currentAST, visit(ctx.annotations())); 1897 DetailAstPair.addAstChild(currentAST, visit(ctx.id())); 1898 DetailAstPair.addAstChild(currentAST, visit(ctx.typeArgumentsOrDiamond())); 1899 1900 // This is how we build the type arguments/ qualified name tree 1901 for (ParserRuleContext extendedContext : ctx.extended) { 1902 final DetailAstImpl dot = create(extendedContext.start); 1903 DetailAstPair.makeAstRoot(currentAST, dot); 1904 final List<ParseTree> childList = extendedContext 1905 .children.subList(1, extendedContext.children.size()); 1906 processChildren(dot, childList); 1907 } 1908 1909 return currentAST.root; 1910 } 1911 1912 @Override 1913 public DetailAstImpl visitCreatedNamePrimitive( 1914 JavaLanguageParser.CreatedNamePrimitiveContext ctx) { 1915 return flattenedTree(ctx); 1916 } 1917 1918 @Override 1919 public DetailAstImpl visitInnerCreator(JavaLanguageParser.InnerCreatorContext ctx) { 1920 return flattenedTree(ctx); 1921 } 1922 1923 @Override 1924 public DetailAstImpl visitArrayCreatorRest(JavaLanguageParser.ArrayCreatorRestContext ctx) { 1925 final DetailAstImpl arrayDeclarator = create(TokenTypes.ARRAY_DECLARATOR, 1926 (Token) ctx.LBRACK().getPayload()); 1927 final JavaLanguageParser.ExpressionContext expression = ctx.expression(); 1928 final TerminalNode rbrack = ctx.RBRACK(); 1929 // child[0] is LBRACK 1930 for (int i = 1; i < ctx.children.size(); i++) { 1931 if (ctx.children.get(i) == rbrack) { 1932 arrayDeclarator.addChild(create(rbrack)); 1933 } 1934 else if (ctx.children.get(i) == expression) { 1935 // Handle '[8]', etc. 1936 arrayDeclarator.addChild(visit(expression)); 1937 } 1938 else { 1939 addLastSibling(arrayDeclarator, visit(ctx.children.get(i))); 1940 } 1941 } 1942 return arrayDeclarator; 1943 } 1944 1945 @Override 1946 public DetailAstImpl visitBracketsWithExp(JavaLanguageParser.BracketsWithExpContext ctx) { 1947 final DetailAstImpl dummyRoot = new DetailAstImpl(); 1948 dummyRoot.addChild(visit(ctx.annotations())); 1949 final DetailAstImpl arrayDeclarator = 1950 create(TokenTypes.ARRAY_DECLARATOR, (Token) ctx.LBRACK().getPayload()); 1951 arrayDeclarator.addChild(visit(ctx.expression())); 1952 arrayDeclarator.addChild(create(ctx.stop)); 1953 dummyRoot.addChild(arrayDeclarator); 1954 return dummyRoot.getFirstChild(); 1955 } 1956 1957 @Override 1958 public DetailAstImpl visitClassCreatorRest(JavaLanguageParser.ClassCreatorRestContext ctx) { 1959 return flattenedTree(ctx); 1960 } 1961 1962 @Override 1963 public DetailAstImpl visitDiamond(JavaLanguageParser.DiamondContext ctx) { 1964 final DetailAstImpl typeArguments = 1965 createImaginary(TokenTypes.TYPE_ARGUMENTS); 1966 typeArguments.addChild(create(TokenTypes.GENERIC_START, 1967 (Token) ctx.LT().getPayload())); 1968 typeArguments.addChild(create(TokenTypes.GENERIC_END, 1969 (Token) ctx.GT().getPayload())); 1970 return typeArguments; 1971 } 1972 1973 @Override 1974 public DetailAstImpl visitTypeArgs(JavaLanguageParser.TypeArgsContext ctx) { 1975 return flattenedTree(ctx); 1976 } 1977 1978 @Override 1979 public DetailAstImpl visitNonWildcardDiamond( 1980 JavaLanguageParser.NonWildcardDiamondContext ctx) { 1981 final DetailAstImpl typeArguments = 1982 createImaginary(TokenTypes.TYPE_ARGUMENTS); 1983 typeArguments.addChild(create(TokenTypes.GENERIC_START, 1984 (Token) ctx.LT().getPayload())); 1985 typeArguments.addChild(create(TokenTypes.GENERIC_END, 1986 (Token) ctx.GT().getPayload())); 1987 return typeArguments; 1988 } 1989 1990 @Override 1991 public DetailAstImpl visitNonWildcardTypeArguments( 1992 JavaLanguageParser.NonWildcardTypeArgumentsContext ctx) { 1993 final DetailAstImpl typeArguments = createImaginary(TokenTypes.TYPE_ARGUMENTS); 1994 typeArguments.addChild(create(TokenTypes.GENERIC_START, (Token) ctx.LT().getPayload())); 1995 typeArguments.addChild(visit(ctx.typeArgumentsTypeList())); 1996 typeArguments.addChild(create(TokenTypes.GENERIC_END, (Token) ctx.GT().getPayload())); 1997 return typeArguments; 1998 } 1999 2000 @Override 2001 public DetailAstImpl visitTypeArgumentsTypeList( 2002 JavaLanguageParser.TypeArgumentsTypeListContext ctx) { 2003 final DetailAstImpl firstIdent = visit(ctx.typeType(0)); 2004 final DetailAstImpl firstTypeArgument = createImaginary(TokenTypes.TYPE_ARGUMENT); 2005 firstTypeArgument.addChild(firstIdent); 2006 2007 for (int i = 0; i < ctx.COMMA().size(); i++) { 2008 addLastSibling(firstTypeArgument, create(ctx.COMMA(i))); 2009 final DetailAstImpl ident = visit(ctx.typeType(i + 1)); 2010 final DetailAstImpl typeArgument = createImaginary(TokenTypes.TYPE_ARGUMENT); 2011 typeArgument.addChild(ident); 2012 addLastSibling(firstTypeArgument, typeArgument); 2013 } 2014 return firstTypeArgument; 2015 } 2016 2017 @Override 2018 public DetailAstImpl visitTypeList(JavaLanguageParser.TypeListContext ctx) { 2019 return flattenedTree(ctx); 2020 } 2021 2022 @Override 2023 public DetailAstImpl visitTypeType(JavaLanguageParser.TypeTypeContext ctx) { 2024 final DetailAstImpl type = createImaginary(TokenTypes.TYPE); 2025 processChildren(type, ctx.children); 2026 2027 final DetailAstImpl returnTree; 2028 if (ctx.createImaginaryNode) { 2029 returnTree = type; 2030 } 2031 else { 2032 returnTree = type.getFirstChild(); 2033 } 2034 return returnTree; 2035 } 2036 2037 @Override 2038 public DetailAstImpl visitArrayDeclarator(JavaLanguageParser.ArrayDeclaratorContext ctx) { 2039 final DetailAstImpl arrayDeclarator = create(TokenTypes.ARRAY_DECLARATOR, 2040 (Token) ctx.LBRACK().getPayload()); 2041 arrayDeclarator.addChild(create(ctx.RBRACK())); 2042 2043 final DetailAstImpl returnTree; 2044 final DetailAstImpl annotations = visit(ctx.anno); 2045 if (annotations == null) { 2046 returnTree = arrayDeclarator; 2047 } 2048 else { 2049 returnTree = annotations; 2050 addLastSibling(returnTree, arrayDeclarator); 2051 } 2052 return returnTree; 2053 } 2054 2055 @Override 2056 public DetailAstImpl visitPrimitiveType(JavaLanguageParser.PrimitiveTypeContext ctx) { 2057 return create(ctx.start); 2058 } 2059 2060 @Override 2061 public DetailAstImpl visitTypeArguments(JavaLanguageParser.TypeArgumentsContext ctx) { 2062 final DetailAstImpl typeArguments = createImaginary(TokenTypes.TYPE_ARGUMENTS); 2063 typeArguments.addChild(create(TokenTypes.GENERIC_START, (Token) ctx.LT().getPayload())); 2064 // Exclude '<' and '>' 2065 processChildren(typeArguments, ctx.children.subList(1, ctx.children.size() - 1)); 2066 typeArguments.addChild(create(TokenTypes.GENERIC_END, (Token) ctx.GT().getPayload())); 2067 return typeArguments; 2068 } 2069 2070 @Override 2071 public DetailAstImpl visitSuperSuffixDot(JavaLanguageParser.SuperSuffixDotContext ctx) { 2072 final DetailAstImpl root; 2073 if (ctx.LPAREN() == null) { 2074 root = create(ctx.DOT()); 2075 root.addChild(visit(ctx.id())); 2076 } 2077 else { 2078 root = create(TokenTypes.METHOD_CALL, (Token) ctx.LPAREN().getPayload()); 2079 2080 final DetailAstImpl dot = create(ctx.DOT()); 2081 dot.addChild(visit(ctx.id())); 2082 root.addChild(dot); 2083 2084 final DetailAstImpl expressionList = Optional.ofNullable(visit(ctx.expressionList())) 2085 .orElseGet(() -> createImaginary(TokenTypes.ELIST)); 2086 root.addChild(expressionList); 2087 2088 root.addChild(create(ctx.RPAREN())); 2089 } 2090 2091 return root; 2092 } 2093 2094 @Override 2095 public DetailAstImpl visitArguments(JavaLanguageParser.ArgumentsContext ctx) { 2096 final DetailAstImpl lparen = create(ctx.LPAREN()); 2097 2098 // We always add an 'ELIST' node 2099 final DetailAstImpl expressionList = Optional.ofNullable(visit(ctx.expressionList())) 2100 .orElseGet(() -> createImaginary(TokenTypes.ELIST)); 2101 addLastSibling(lparen, expressionList); 2102 addLastSibling(lparen, create(ctx.RPAREN())); 2103 return lparen; 2104 } 2105 2106 @Override 2107 public DetailAstImpl visitPattern(JavaLanguageParser.PatternContext ctx) { 2108 final JavaLanguageParser.InnerPatternContext innerPattern = ctx.innerPattern(); 2109 final ParserRuleContext primaryPattern = innerPattern.primaryPattern(); 2110 final ParserRuleContext recordPattern = innerPattern.recordPattern(); 2111 final boolean isSimpleTypePattern = primaryPattern != null 2112 && primaryPattern.getChild(0) instanceof JavaLanguageParser.TypePatternContext; 2113 2114 final DetailAstImpl pattern; 2115 2116 if (recordPattern != null) { 2117 pattern = visit(recordPattern); 2118 } 2119 else if (isSimpleTypePattern) { 2120 // For simple type pattern like 'Integer i`, we do not add `PATTERN_DEF` parent 2121 pattern = visit(primaryPattern); 2122 } 2123 else { 2124 pattern = createImaginary(TokenTypes.PATTERN_DEF); 2125 pattern.addChild(visit(ctx.getChild(0))); 2126 } 2127 return pattern; 2128 } 2129 2130 @Override 2131 public DetailAstImpl visitInnerPattern(JavaLanguageParser.InnerPatternContext ctx) { 2132 return flattenedTree(ctx); 2133 } 2134 2135 @Override 2136 public DetailAstImpl visitGuardedPattern(JavaLanguageParser.GuardedPatternContext ctx) { 2137 final DetailAstImpl guardAstNode = flattenedTree(ctx.guard()); 2138 guardAstNode.addChild(visit(ctx.primaryPattern())); 2139 guardAstNode.addChild(visit(ctx.expr())); 2140 return guardAstNode; 2141 } 2142 2143 @Override 2144 public DetailAstImpl visitParenPattern(JavaLanguageParser.ParenPatternContext ctx) { 2145 final DetailAstImpl lparen = create(ctx.LPAREN()); 2146 final ParseTree innerPattern = ctx.getChild(1); 2147 lparen.addChild(visit(innerPattern)); 2148 lparen.addChild(create(ctx.RPAREN())); 2149 return lparen; 2150 } 2151 2152 @Override 2153 public DetailAstImpl visitRecordPatternDef(JavaLanguageParser.RecordPatternDefContext ctx) { 2154 return flattenedTree(ctx); 2155 } 2156 2157 @Override 2158 public DetailAstImpl visitTypePatternDef( 2159 JavaLanguageParser.TypePatternDefContext ctx) { 2160 final DetailAstImpl type = visit(ctx.type); 2161 final DetailAstImpl patternVariableDef = createImaginary(TokenTypes.PATTERN_VARIABLE_DEF); 2162 patternVariableDef.addChild(createModifiers(ctx.mods)); 2163 patternVariableDef.addChild(type); 2164 patternVariableDef.addChild(visit(ctx.id())); 2165 return patternVariableDef; 2166 } 2167 2168 @Override 2169 public DetailAstImpl visitUnnamedPatternDef(JavaLanguageParser.UnnamedPatternDefContext ctx) { 2170 return create(TokenTypes.UNNAMED_PATTERN_DEF, ctx.start); 2171 } 2172 2173 @Override 2174 public DetailAstImpl visitRecordPattern(JavaLanguageParser.RecordPatternContext ctx) { 2175 final DetailAstImpl recordPattern = createImaginary(TokenTypes.RECORD_PATTERN_DEF); 2176 recordPattern.addChild(createModifiers(ctx.mods)); 2177 processChildren(recordPattern, 2178 ctx.children.subList(ctx.mods.size(), ctx.children.size())); 2179 return recordPattern; 2180 } 2181 2182 @Override 2183 public DetailAstImpl visitRecordComponentPatternList( 2184 JavaLanguageParser.RecordComponentPatternListContext ctx) { 2185 final DetailAstImpl recordComponents = 2186 createImaginary(TokenTypes.RECORD_PATTERN_COMPONENTS); 2187 processChildren(recordComponents, ctx.children); 2188 return recordComponents; 2189 } 2190 2191 @Override 2192 public DetailAstImpl visitPermittedSubclassesAndInterfaces( 2193 JavaLanguageParser.PermittedSubclassesAndInterfacesContext ctx) { 2194 final DetailAstImpl literalPermits = 2195 create(TokenTypes.PERMITS_CLAUSE, (Token) ctx.LITERAL_PERMITS().getPayload()); 2196 // 'LITERAL_PERMITS' is child[0] 2197 processChildren(literalPermits, ctx.children.subList(1, ctx.children.size())); 2198 return literalPermits; 2199 } 2200 2201 @Override 2202 public DetailAstImpl visitId(JavaLanguageParser.IdContext ctx) { 2203 return create(TokenTypes.IDENT, ctx.start); 2204 } 2205 2206 /** 2207 * Builds the AST for a particular node, then returns a "flattened" tree 2208 * of siblings. This method should be used in rule contexts such as 2209 * {@code variableDeclarators}, where we have both terminals and non-terminals. 2210 * 2211 * @param ctx the ParserRuleContext to base tree on 2212 * @return flattened DetailAstImpl 2213 */ 2214 private DetailAstImpl flattenedTree(ParserRuleContext ctx) { 2215 final DetailAstImpl dummyNode = new DetailAstImpl(); 2216 processChildren(dummyNode, ctx.children); 2217 return dummyNode.getFirstChild(); 2218 } 2219 2220 /** 2221 * Adds all the children from the given ParseTree or JavaParserContext 2222 * list to the parent DetailAstImpl. 2223 * 2224 * @param parent the DetailAstImpl to add children to 2225 * @param children the list of children to add 2226 */ 2227 private void processChildren(DetailAstImpl parent, List<? extends ParseTree> children) { 2228 children.forEach(child -> { 2229 if (child instanceof TerminalNode) { 2230 // Child is a token, create a new DetailAstImpl and add it to parent 2231 parent.addChild(create((TerminalNode) child)); 2232 } 2233 else { 2234 // Child is another rule context; visit it, create token, and add to parent 2235 parent.addChild(visit(child)); 2236 } 2237 }); 2238 } 2239 2240 /** 2241 * Create a DetailAstImpl from a given token and token type. This method 2242 * should be used for imaginary nodes only, i.e. 'OBJBLOCK -> OBJBLOCK', 2243 * where the text on the RHS matches the text on the LHS. 2244 * 2245 * @param tokenType the token type of this DetailAstImpl 2246 * @return new DetailAstImpl of given type 2247 */ 2248 private static DetailAstImpl createImaginary(int tokenType) { 2249 final DetailAstImpl detailAst = new DetailAstImpl(); 2250 detailAst.setType(tokenType); 2251 detailAst.setText(TokenUtil.getTokenName(tokenType)); 2252 return detailAst; 2253 } 2254 2255 /** 2256 * Create a DetailAstImpl from a given token type and text. This method 2257 * should be used for imaginary nodes only, i.e. 'OBJBLOCK -> OBJBLOCK', 2258 * where the text on the RHS matches the text on the LHS. 2259 * 2260 * @param tokenType the token type of this DetailAstImpl 2261 * @param text the text of this DetailAstImpl 2262 * @return new DetailAstImpl of given type 2263 */ 2264 private static DetailAstImpl createImaginary(int tokenType, String text) { 2265 final DetailAstImpl imaginary = new DetailAstImpl(); 2266 imaginary.setType(tokenType); 2267 imaginary.setText(text); 2268 return imaginary; 2269 } 2270 2271 /** 2272 * Creates an imaginary DetailAstImpl with the given token details. 2273 * 2274 * @param tokenType the token type of this DetailAstImpl 2275 * @param text the text of this DetailAstImpl 2276 * @param lineNumber the line number of this DetailAstImpl 2277 * @param columnNumber the column number of this DetailAstImpl 2278 * @return imaginary DetailAstImpl from given details 2279 */ 2280 private static DetailAstImpl createImaginary( 2281 int tokenType, String text, int lineNumber, int columnNumber) { 2282 final DetailAstImpl imaginary = createImaginary(tokenType, text); 2283 imaginary.setLineNo(lineNumber); 2284 imaginary.setColumnNo(columnNumber); 2285 return imaginary; 2286 } 2287 2288 /** 2289 * Create a DetailAstImpl from a given token and token type. This method 2290 * should be used for literal nodes only, i.e. 'PACKAGE_DEF -> package'. 2291 * 2292 * @param tokenType the token type of this DetailAstImpl 2293 * @param startToken the first token that appears in this DetailAstImpl. 2294 * @return new DetailAstImpl of given type 2295 */ 2296 private DetailAstImpl create(int tokenType, Token startToken) { 2297 final DetailAstImpl ast = create(startToken); 2298 ast.setType(tokenType); 2299 return ast; 2300 } 2301 2302 /** 2303 * Create a DetailAstImpl from a given token. This method should be 2304 * used for terminal nodes, i.e. {@code LCURLY}, when we are building 2305 * an AST for a specific token, regardless of position. 2306 * 2307 * @param token the token to build the DetailAstImpl from 2308 * @return new DetailAstImpl of given type 2309 */ 2310 private DetailAstImpl create(Token token) { 2311 final int tokenIndex = token.getTokenIndex(); 2312 final List<Token> tokensToLeft = 2313 tokens.getHiddenTokensToLeft(tokenIndex, JavaLanguageLexer.COMMENTS); 2314 final List<Token> tokensToRight = 2315 tokens.getHiddenTokensToRight(tokenIndex, JavaLanguageLexer.COMMENTS); 2316 2317 final DetailAstImpl detailAst = new DetailAstImpl(); 2318 detailAst.initialize(token); 2319 if (tokensToLeft != null) { 2320 detailAst.setHiddenBefore(tokensToLeft); 2321 } 2322 if (tokensToRight != null) { 2323 detailAst.setHiddenAfter(tokensToRight); 2324 } 2325 return detailAst; 2326 } 2327 2328 /** 2329 * Create a DetailAstImpl from a given TerminalNode. This method should be 2330 * used for terminal nodes, i.e. {@code @}. 2331 * 2332 * @param node the TerminalNode to build the DetailAstImpl from 2333 * @return new DetailAstImpl of given type 2334 */ 2335 private DetailAstImpl create(TerminalNode node) { 2336 return create((Token) node.getPayload()); 2337 } 2338 2339 /** 2340 * Creates a type declaration DetailAstImpl from a given rule context. 2341 * 2342 * @param ctx ParserRuleContext we are in 2343 * @param type the type declaration to create 2344 * @param modifierList respective modifiers 2345 * @return type declaration DetailAstImpl 2346 */ 2347 private DetailAstImpl createTypeDeclaration(ParserRuleContext ctx, int type, 2348 List<? extends ParseTree> modifierList) { 2349 final DetailAstImpl typeDeclaration = createImaginary(type); 2350 typeDeclaration.addChild(createModifiers(modifierList)); 2351 processChildren(typeDeclaration, ctx.children); 2352 return typeDeclaration; 2353 } 2354 2355 /** 2356 * Builds the modifiers AST. 2357 * 2358 * @param modifierList the list of modifier contexts 2359 * @return "MODIFIERS" ast 2360 */ 2361 private DetailAstImpl createModifiers(List<? extends ParseTree> modifierList) { 2362 final DetailAstImpl mods = createImaginary(TokenTypes.MODIFIERS); 2363 processChildren(mods, modifierList); 2364 return mods; 2365 } 2366 2367 /** 2368 * Add new sibling to the end of existing siblings. 2369 * 2370 * @param self DetailAstImpl to add last sibling to 2371 * @param sibling DetailAstImpl sibling to add 2372 */ 2373 private static void addLastSibling(DetailAstImpl self, DetailAstImpl sibling) { 2374 DetailAstImpl nextSibling = self; 2375 if (nextSibling != null) { 2376 while (nextSibling.getNextSibling() != null) { 2377 nextSibling = nextSibling.getNextSibling(); 2378 } 2379 nextSibling.setNextSibling(sibling); 2380 } 2381 } 2382 2383 @Override 2384 public DetailAstImpl visit(ParseTree tree) { 2385 DetailAstImpl ast = null; 2386 if (tree != null) { 2387 ast = tree.accept(this); 2388 } 2389 return ast; 2390 } 2391 2392 /** 2393 * Builds an expression node. This is used to build the root of an expression with 2394 * an imaginary {@code EXPR} node. 2395 * 2396 * @param exprNode expression to build node for 2397 * @return expression DetailAstImpl node 2398 */ 2399 private DetailAstImpl buildExpressionNode(ParseTree exprNode) { 2400 final DetailAstImpl expression = visit(exprNode); 2401 2402 final DetailAstImpl exprRoot; 2403 if (TokenUtil.isOfType(expression, EXPRESSIONS_WITH_NO_EXPR_ROOT)) { 2404 exprRoot = expression; 2405 } 2406 else { 2407 // create imaginary 'EXPR' node as root of expression 2408 exprRoot = createImaginary(TokenTypes.EXPR); 2409 exprRoot.addChild(expression); 2410 } 2411 return exprRoot; 2412 } 2413 2414 /** 2415 * Used to swap and organize DetailAstImpl subtrees. 2416 */ 2417 private static final class DetailAstPair { 2418 2419 /** The root DetailAstImpl of this pair. */ 2420 private DetailAstImpl root; 2421 2422 /** The child (potentially with siblings) of this pair. */ 2423 private DetailAstImpl child; 2424 2425 /** 2426 * Moves child reference to the last child. 2427 */ 2428 private void advanceChildToEnd() { 2429 while (child.getNextSibling() != null) { 2430 child = child.getNextSibling(); 2431 } 2432 } 2433 2434 /** 2435 * Returns the root node. 2436 * 2437 * @return the root node 2438 */ 2439 private DetailAstImpl getRoot() { 2440 return root; 2441 } 2442 2443 /** 2444 * This method is used to replace the {@code ^} (set as root node) ANTLR2 2445 * operator. 2446 * 2447 * @param pair the DetailAstPair to use for swapping nodes 2448 * @param ast the new root 2449 */ 2450 private static void makeAstRoot(DetailAstPair pair, DetailAstImpl ast) { 2451 ast.addChild(pair.root); 2452 pair.child = pair.root; 2453 pair.advanceChildToEnd(); 2454 pair.root = ast; 2455 } 2456 2457 /** 2458 * Adds a child (or new root) to the given DetailAstPair. 2459 * 2460 * @param pair the DetailAstPair to add child to 2461 * @param ast the child to add 2462 */ 2463 private static void addAstChild(DetailAstPair pair, DetailAstImpl ast) { 2464 if (ast != null) { 2465 if (pair.root == null) { 2466 pair.root = ast; 2467 } 2468 else { 2469 pair.child.setNextSibling(ast); 2470 } 2471 pair.child = ast; 2472 } 2473 } 2474 } 2475}