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