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