001//////////////////////////////////////////////////////////////////////////////// 002// checkstyle: Checks Java source code for adherence to a set of rules. 003// Copyright (C) 2001-2021 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 (int i = 0; i < ctx.extended.size(); i++) { 556 final ParserRuleContext extendedContext = ctx.extended.get(i); 557 final DetailAstImpl dot = create(extendedContext.start); 558 DetailAstPair.makeAstRoot(currentAST, dot); 559 final List<ParseTree> childList = extendedContext 560 .children.subList(1, extendedContext.children.size()); 561 childList.forEach(child -> DetailAstPair.addAstChild(currentAST, visit(child))); 562 } 563 564 // Create imaginary 'TYPE' parent if specified 565 final DetailAstImpl returnTree; 566 if (ctx.createImaginaryNode) { 567 returnTree = createImaginary(TokenTypes.TYPE); 568 returnTree.addChild(currentAST.root); 569 } 570 else { 571 returnTree = currentAST.root; 572 } 573 return returnTree; 574 } 575 576 @Override 577 public DetailAstImpl visitSimpleTypeArgument( 578 JavaLanguageParser.SimpleTypeArgumentContext ctx) { 579 final DetailAstImpl typeArgument = 580 createImaginary(TokenTypes.TYPE_ARGUMENT); 581 typeArgument.addChild(visit(ctx.typeType())); 582 return typeArgument; 583 } 584 585 @Override 586 public DetailAstImpl visitWildCardTypeArgument( 587 JavaLanguageParser.WildCardTypeArgumentContext ctx) { 588 final DetailAstImpl typeArgument = createImaginary(TokenTypes.TYPE_ARGUMENT); 589 typeArgument.addChild(visit(ctx.annotations())); 590 typeArgument.addChild(create(TokenTypes.WILDCARD_TYPE, 591 (Token) ctx.QUESTION().getPayload())); 592 593 if (ctx.upperBound != null) { 594 final DetailAstImpl upperBound = create(TokenTypes.TYPE_UPPER_BOUNDS, ctx.upperBound); 595 upperBound.addChild(visit(ctx.typeType())); 596 typeArgument.addChild(upperBound); 597 } 598 else if (ctx.lowerBound != null) { 599 final DetailAstImpl lowerBound = create(TokenTypes.TYPE_LOWER_BOUNDS, ctx.lowerBound); 600 lowerBound.addChild(visit(ctx.typeType())); 601 typeArgument.addChild(lowerBound); 602 } 603 604 return typeArgument; 605 } 606 607 @Override 608 public DetailAstImpl visitQualifiedNameList(JavaLanguageParser.QualifiedNameListContext ctx) { 609 return flattenedTree(ctx); 610 } 611 612 @Override 613 public DetailAstImpl visitFormalParameters(JavaLanguageParser.FormalParametersContext ctx) { 614 final DetailAstImpl lparen = create(ctx.LPAREN()); 615 616 // We make a "PARAMETERS" node whether parameters exist or not 617 if (ctx.formalParameterList() == null) { 618 addLastSibling(lparen, createImaginary(TokenTypes.PARAMETERS)); 619 } 620 else { 621 addLastSibling(lparen, visit(ctx.formalParameterList())); 622 } 623 addLastSibling(lparen, create(ctx.RPAREN())); 624 return lparen; 625 } 626 627 @Override 628 public DetailAstImpl visitFormalParameterList( 629 JavaLanguageParser.FormalParameterListContext ctx) { 630 final DetailAstImpl parameters = createImaginary(TokenTypes.PARAMETERS); 631 processChildren(parameters, ctx.children); 632 return parameters; 633 } 634 635 @Override 636 public DetailAstImpl visitFormalParameter(JavaLanguageParser.FormalParameterContext ctx) { 637 final DetailAstImpl variableDeclaratorId = 638 visitVariableDeclaratorId(ctx.variableDeclaratorId()); 639 final DetailAstImpl parameterDef = createImaginary(TokenTypes.PARAMETER_DEF); 640 parameterDef.addChild(variableDeclaratorId); 641 return parameterDef; 642 } 643 644 @Override 645 public DetailAstImpl visitLastFormalParameter( 646 JavaLanguageParser.LastFormalParameterContext ctx) { 647 final DetailAstImpl parameterDef = 648 createImaginary(TokenTypes.PARAMETER_DEF); 649 parameterDef.addChild(visit(ctx.variableDeclaratorId())); 650 final DetailAstImpl ident = (DetailAstImpl) parameterDef.findFirstToken(TokenTypes.IDENT); 651 ident.addPreviousSibling(create(ctx.ELLIPSIS())); 652 // We attach annotations on ellipses in varargs to the 'TYPE' ast 653 final DetailAstImpl type = (DetailAstImpl) parameterDef.findFirstToken(TokenTypes.TYPE); 654 type.addChild(visit(ctx.annotations())); 655 return parameterDef; 656 } 657 658 @Override 659 public DetailAstImpl visitQualifiedName(JavaLanguageParser.QualifiedNameContext ctx) { 660 final DetailAstImpl ast = visit(ctx.id()); 661 final DetailAstPair currentAst = new DetailAstPair(); 662 DetailAstPair.addAstChild(currentAst, ast); 663 664 for (int i = 0; i < ctx.extended.size(); i++) { 665 final ParserRuleContext extendedContext = ctx.extended.get(i); 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 visitEnhancedFor(JavaLanguageParser.EnhancedForContext ctx) { 1221 final DetailAstImpl leftParen = create(ctx.LPAREN()); 1222 final DetailAstImpl enhancedForControl = 1223 visit(ctx.enhancedForControl()); 1224 final DetailAstImpl forEachClause = createImaginary(TokenTypes.FOR_EACH_CLAUSE); 1225 forEachClause.addChild(enhancedForControl); 1226 addLastSibling(leftParen, forEachClause); 1227 addLastSibling(leftParen, create(ctx.RPAREN())); 1228 return leftParen; 1229 } 1230 1231 @Override 1232 public DetailAstImpl visitForFor(JavaLanguageParser.ForForContext ctx) { 1233 final DetailAstImpl dummyRoot = new DetailAstImpl(); 1234 dummyRoot.addChild(create(ctx.LPAREN())); 1235 1236 if (ctx.forInit() == null) { 1237 final DetailAstImpl imaginaryForInitParent = 1238 createImaginary(TokenTypes.FOR_INIT); 1239 dummyRoot.addChild(imaginaryForInitParent); 1240 } 1241 else { 1242 dummyRoot.addChild(visit(ctx.forInit())); 1243 } 1244 1245 dummyRoot.addChild(create(ctx.SEMI(0))); 1246 1247 final DetailAstImpl forCondParent = createImaginary(TokenTypes.FOR_CONDITION); 1248 forCondParent.addChild(visit(ctx.forCond)); 1249 dummyRoot.addChild(forCondParent); 1250 dummyRoot.addChild(create(ctx.SEMI(1))); 1251 1252 final DetailAstImpl forItParent = createImaginary(TokenTypes.FOR_ITERATOR); 1253 forItParent.addChild(visit(ctx.forUpdate)); 1254 dummyRoot.addChild(forItParent); 1255 1256 dummyRoot.addChild(create(ctx.RPAREN())); 1257 1258 return dummyRoot.getFirstChild(); 1259 } 1260 1261 @Override 1262 public DetailAstImpl visitForInit(JavaLanguageParser.ForInitContext ctx) { 1263 final DetailAstImpl forInit = createImaginary(TokenTypes.FOR_INIT); 1264 processChildren(forInit, ctx.children); 1265 return forInit; 1266 } 1267 1268 @Override 1269 public DetailAstImpl visitEnhancedForControl( 1270 JavaLanguageParser.EnhancedForControlContext ctx) { 1271 final DetailAstImpl variableDeclaratorId = 1272 visit(ctx.variableDeclaratorId()); 1273 final DetailAstImpl variableDef = createImaginary(TokenTypes.VARIABLE_DEF); 1274 variableDef.addChild(variableDeclaratorId); 1275 1276 addLastSibling(variableDef, create(ctx.COLON())); 1277 addLastSibling(variableDef, visit(ctx.expression())); 1278 return variableDef; 1279 } 1280 1281 @Override 1282 public DetailAstImpl visitParExpression(JavaLanguageParser.ParExpressionContext ctx) { 1283 return flattenedTree(ctx); 1284 } 1285 1286 @Override 1287 public DetailAstImpl visitExpressionList(JavaLanguageParser.ExpressionListContext ctx) { 1288 final DetailAstImpl elist = createImaginary(TokenTypes.ELIST); 1289 processChildren(elist, ctx.children); 1290 return elist; 1291 } 1292 1293 @Override 1294 public DetailAstImpl visitExpression(JavaLanguageParser.ExpressionContext ctx) { 1295 final DetailAstImpl expression = visit(ctx.expr()); 1296 DetailAstImpl exprRoot = createImaginary(TokenTypes.EXPR); 1297 exprRoot.addChild(expression); 1298 1299 final int[] expressionsWithNoExprRoot = { 1300 TokenTypes.CTOR_CALL, 1301 TokenTypes.SUPER_CTOR_CALL, 1302 TokenTypes.LAMBDA, 1303 }; 1304 1305 if (TokenUtil.isOfType(expression, expressionsWithNoExprRoot)) { 1306 exprRoot = exprRoot.getFirstChild(); 1307 } 1308 1309 return exprRoot; 1310 } 1311 1312 @Override 1313 public DetailAstImpl visitRefOp(JavaLanguageParser.RefOpContext ctx) { 1314 final DetailAstImpl bop = create(ctx.bop); 1315 final DetailAstImpl leftChild = visit(ctx.expr()); 1316 final DetailAstImpl rightChild = create(TokenTypes.IDENT, ctx.stop); 1317 bop.addChild(leftChild); 1318 bop.addChild(rightChild); 1319 return bop; 1320 } 1321 1322 @Override 1323 public DetailAstImpl visitSuperExp(JavaLanguageParser.SuperExpContext ctx) { 1324 final DetailAstImpl bop = create(ctx.bop); 1325 bop.addChild(visit(ctx.expr())); 1326 bop.addChild(create(ctx.LITERAL_SUPER())); 1327 DetailAstImpl superSuffixParent = visit(ctx.superSuffix()); 1328 1329 if (superSuffixParent == null) { 1330 superSuffixParent = bop; 1331 } 1332 else { 1333 DetailAstImpl firstChild = superSuffixParent.getFirstChild(); 1334 while (firstChild.getFirstChild() != null) { 1335 firstChild = firstChild.getFirstChild(); 1336 } 1337 firstChild.addPreviousSibling(bop); 1338 } 1339 1340 return superSuffixParent; 1341 } 1342 1343 @Override 1344 public DetailAstImpl visitInstanceOfExp(JavaLanguageParser.InstanceOfExpContext ctx) { 1345 final DetailAstImpl literalInstanceOf = create(ctx.LITERAL_INSTANCEOF()); 1346 literalInstanceOf.addChild(visit(ctx.expr())); 1347 literalInstanceOf.addChild(visit(ctx.children.get(2))); 1348 return literalInstanceOf; 1349 } 1350 1351 @Override 1352 public DetailAstImpl visitBitShift(JavaLanguageParser.BitShiftContext ctx) { 1353 final DetailAstImpl shiftOperation; 1354 1355 // We determine the type of shift operation in the parser, instead of the 1356 // lexer as in older grammars. This makes it easier to parse type parameters 1357 // and less than/ greater than operators in general. 1358 if (ctx.LT().size() == LEFT_SHIFT.length()) { 1359 shiftOperation = create(TokenTypes.SL, (Token) ctx.LT(0).getPayload()); 1360 shiftOperation.setText(LEFT_SHIFT); 1361 } 1362 else if (ctx.GT().size() == UNSIGNED_RIGHT_SHIFT.length()) { 1363 shiftOperation = create(TokenTypes.BSR, (Token) ctx.GT(0).getPayload()); 1364 shiftOperation.setText(UNSIGNED_RIGHT_SHIFT); 1365 } 1366 else { 1367 shiftOperation = create(TokenTypes.SR, (Token) ctx.GT(0).getPayload()); 1368 shiftOperation.setText(RIGHT_SHIFT); 1369 } 1370 1371 shiftOperation.addChild(visit(ctx.expr(0))); 1372 shiftOperation.addChild(visit(ctx.expr(1))); 1373 return shiftOperation; 1374 } 1375 1376 @Override 1377 public DetailAstImpl visitNewExp(JavaLanguageParser.NewExpContext ctx) { 1378 final DetailAstImpl newExp = create(ctx.LITERAL_NEW()); 1379 // child [0] is LITERAL_NEW 1380 processChildren(newExp, ctx.children.subList(1, ctx.children.size())); 1381 return newExp; 1382 } 1383 1384 @Override 1385 public DetailAstImpl visitPrefix(JavaLanguageParser.PrefixContext ctx) { 1386 final int tokenType; 1387 switch (ctx.prefix.getType()) { 1388 case JavaLanguageLexer.PLUS: 1389 tokenType = TokenTypes.UNARY_PLUS; 1390 break; 1391 case JavaLanguageLexer.MINUS: 1392 tokenType = TokenTypes.UNARY_MINUS; 1393 break; 1394 default: 1395 tokenType = ctx.prefix.getType(); 1396 } 1397 final DetailAstImpl prefix = create(tokenType, ctx.prefix); 1398 prefix.addChild(visit(ctx.expr())); 1399 return prefix; 1400 } 1401 1402 @Override 1403 public DetailAstImpl visitCastExp(JavaLanguageParser.CastExpContext ctx) { 1404 final DetailAstImpl cast = create(TokenTypes.TYPECAST, (Token) ctx.LPAREN().getPayload()); 1405 // child [0] is LPAREN 1406 processChildren(cast, ctx.children.subList(1, ctx.children.size())); 1407 return cast; 1408 } 1409 1410 @Override 1411 public DetailAstImpl visitIndexOp(JavaLanguageParser.IndexOpContext ctx) { 1412 // LBRACK -> INDEX_OP is root of this AST 1413 final DetailAstImpl indexOp = create(TokenTypes.INDEX_OP, 1414 (Token) ctx.LBRACK().getPayload()); 1415 1416 // add expression(IDENT) on LHS 1417 indexOp.addChild(visit(ctx.expr(0))); 1418 1419 // create imaginary node for expression on RHS 1420 final DetailAstImpl expr = visit(ctx.expr(1)); 1421 final DetailAstImpl imaginaryExpr = createImaginary(TokenTypes.EXPR); 1422 imaginaryExpr.addChild(expr); 1423 indexOp.addChild(imaginaryExpr); 1424 1425 // complete AST by adding RBRACK 1426 indexOp.addChild(create(ctx.RBRACK())); 1427 return indexOp; 1428 } 1429 1430 @Override 1431 public DetailAstImpl visitInvOp(JavaLanguageParser.InvOpContext ctx) { 1432 final DetailAstPair currentAst = new DetailAstPair(); 1433 1434 final DetailAstImpl returnAst = visit(ctx.expr()); 1435 DetailAstPair.addAstChild(currentAst, returnAst); 1436 DetailAstPair.makeAstRoot(currentAst, create(ctx.bop)); 1437 1438 DetailAstPair.addAstChild(currentAst, 1439 visit(ctx.nonWildcardTypeArguments())); 1440 DetailAstPair.addAstChild(currentAst, visit(ctx.id())); 1441 final DetailAstImpl lparen = create(TokenTypes.METHOD_CALL, 1442 (Token) ctx.LPAREN().getPayload()); 1443 DetailAstPair.makeAstRoot(currentAst, lparen); 1444 1445 // We always add an 'ELIST' node 1446 final DetailAstImpl expressionList = Optional.ofNullable(visit(ctx.expressionList())) 1447 .orElse(createImaginary(TokenTypes.ELIST)); 1448 1449 DetailAstPair.addAstChild(currentAst, expressionList); 1450 DetailAstPair.addAstChild(currentAst, create(ctx.RPAREN())); 1451 1452 return currentAst.root; 1453 } 1454 1455 @Override 1456 public DetailAstImpl visitInitExp(JavaLanguageParser.InitExpContext ctx) { 1457 final DetailAstImpl dot = create(ctx.bop); 1458 dot.addChild(visit(ctx.expr())); 1459 final DetailAstImpl literalNew = create(ctx.LITERAL_NEW()); 1460 literalNew.addChild(visit(ctx.nonWildcardTypeArguments())); 1461 literalNew.addChild(visit(ctx.innerCreator())); 1462 dot.addChild(literalNew); 1463 return dot; 1464 } 1465 1466 @Override 1467 public DetailAstImpl visitSimpleMethodCall(JavaLanguageParser.SimpleMethodCallContext ctx) { 1468 final DetailAstImpl methodCall = create(TokenTypes.METHOD_CALL, 1469 (Token) ctx.LPAREN().getPayload()); 1470 methodCall.addChild(visit(ctx.id())); 1471 // We always add an 'ELIST' node 1472 final DetailAstImpl expressionList = Optional.ofNullable(visit(ctx.expressionList())) 1473 .orElse(createImaginary(TokenTypes.ELIST)); 1474 1475 methodCall.addChild(expressionList); 1476 methodCall.addChild(create((Token) ctx.RPAREN().getPayload())); 1477 return methodCall; 1478 } 1479 1480 @Override 1481 public DetailAstImpl visitLambdaExp(JavaLanguageParser.LambdaExpContext ctx) { 1482 return flattenedTree(ctx); 1483 } 1484 1485 @Override 1486 public DetailAstImpl visitThisExp(JavaLanguageParser.ThisExpContext ctx) { 1487 final DetailAstImpl bop = create(ctx.bop); 1488 bop.addChild(visit(ctx.expr())); 1489 bop.addChild(create(ctx.LITERAL_THIS())); 1490 return bop; 1491 } 1492 1493 @Override 1494 public DetailAstImpl visitPrimaryExp(JavaLanguageParser.PrimaryExpContext ctx) { 1495 return flattenedTree(ctx); 1496 } 1497 1498 @Override 1499 public DetailAstImpl visitPostfix(JavaLanguageParser.PostfixContext ctx) { 1500 final DetailAstImpl postfix; 1501 if (ctx.postfix.getType() == JavaLanguageLexer.INC) { 1502 postfix = create(TokenTypes.POST_INC, ctx.postfix); 1503 } 1504 else { 1505 postfix = create(TokenTypes.POST_DEC, ctx.postfix); 1506 } 1507 postfix.addChild(visit(ctx.expr())); 1508 return postfix; 1509 } 1510 1511 @Override 1512 public DetailAstImpl visitMethodRef(JavaLanguageParser.MethodRefContext ctx) { 1513 final DetailAstImpl doubleColon = create(TokenTypes.METHOD_REF, 1514 (Token) ctx.DOUBLE_COLON().getPayload()); 1515 final List<ParseTree> children = ctx.children.stream() 1516 .filter(child -> !child.equals(ctx.DOUBLE_COLON())) 1517 .collect(Collectors.toList()); 1518 processChildren(doubleColon, children); 1519 return doubleColon; 1520 } 1521 1522 @Override 1523 public DetailAstImpl visitTernaryOp(JavaLanguageParser.TernaryOpContext ctx) { 1524 final DetailAstImpl root = create(ctx.QUESTION()); 1525 processChildren(root, ctx.children.stream() 1526 .filter(child -> !child.equals(ctx.QUESTION())) 1527 .collect(Collectors.toList())); 1528 return root; 1529 } 1530 1531 @Override 1532 public DetailAstImpl visitBinOp(JavaLanguageParser.BinOpContext ctx) { 1533 final DetailAstImpl bop = create(ctx.bop); 1534 1535 // To improve performance, we iterate through binary operations 1536 // since they are frequently deeply nested. 1537 final List<JavaLanguageParser.BinOpContext> binOpList = new ArrayList<>(); 1538 ParseTree firstExpression = ctx.expr(0); 1539 while (firstExpression instanceof JavaLanguageParser.BinOpContext) { 1540 // Get all nested binOps 1541 binOpList.add((JavaLanguageParser.BinOpContext) firstExpression); 1542 firstExpression = ((JavaLanguageParser.BinOpContext) firstExpression).expr(0); 1543 } 1544 1545 if (binOpList.isEmpty()) { 1546 final DetailAstImpl leftChild = visit(ctx.children.get(0)); 1547 bop.addChild(leftChild); 1548 } 1549 else { 1550 // Map all descendants to individual AST's since we can parallelize this 1551 // operation 1552 final Queue<DetailAstImpl> descendantList = binOpList.parallelStream() 1553 .map(this::getInnerBopAst) 1554 .collect(Collectors.toCollection(ConcurrentLinkedQueue::new)); 1555 1556 bop.addChild(descendantList.poll()); 1557 DetailAstImpl pointer = bop.getFirstChild(); 1558 // Build tree 1559 for (DetailAstImpl descendant : descendantList) { 1560 pointer.getFirstChild().addPreviousSibling(descendant); 1561 pointer = descendant; 1562 } 1563 } 1564 1565 bop.addChild(visit(ctx.children.get(2))); 1566 return bop; 1567 } 1568 1569 /** 1570 * Builds the binary operation (binOp) AST. 1571 * 1572 * @param descendant the BinOpContext to build AST from 1573 * @return binOp AST 1574 */ 1575 private DetailAstImpl getInnerBopAst(JavaLanguageParser.BinOpContext descendant) { 1576 final DetailAstImpl innerBop = create(descendant.bop); 1577 if (!(descendant.expr(0) instanceof JavaLanguageParser.BinOpContext)) { 1578 innerBop.addChild(visit(descendant.expr(0))); 1579 } 1580 innerBop.addChild(visit(descendant.expr(1))); 1581 return innerBop; 1582 } 1583 1584 @Override 1585 public DetailAstImpl visitMethodCall(JavaLanguageParser.MethodCallContext ctx) { 1586 final DetailAstImpl methodCall = create(TokenTypes.METHOD_CALL, 1587 (Token) ctx.LPAREN().getPayload()); 1588 // We always add an 'ELIST' node 1589 final DetailAstImpl expressionList = Optional.ofNullable(visit(ctx.expressionList())) 1590 .orElse(createImaginary(TokenTypes.ELIST)); 1591 1592 final DetailAstImpl dot = create(ctx.DOT()); 1593 dot.addChild(visit(ctx.expr())); 1594 dot.addChild(visit(ctx.id())); 1595 methodCall.addChild(dot); 1596 methodCall.addChild(expressionList); 1597 methodCall.addChild(create((Token) ctx.RPAREN().getPayload())); 1598 return methodCall; 1599 } 1600 1601 @Override 1602 public DetailAstImpl visitTypeCastParameters( 1603 JavaLanguageParser.TypeCastParametersContext ctx) { 1604 final DetailAstImpl typeType = visit(ctx.typeType(0)); 1605 for (int i = 0; i < ctx.BAND().size(); i++) { 1606 addLastSibling(typeType, create(TokenTypes.TYPE_EXTENSION_AND, 1607 (Token) ctx.BAND(i).getPayload())); 1608 addLastSibling(typeType, visit(ctx.typeType(i + 1))); 1609 } 1610 return typeType; 1611 } 1612 1613 @Override 1614 public DetailAstImpl visitLambdaExpression(JavaLanguageParser.LambdaExpressionContext ctx) { 1615 final DetailAstImpl lambda = create(ctx.LAMBDA()); 1616 lambda.addChild(visit(ctx.lambdaParameters())); 1617 lambda.addChild(visit(ctx.lambdaBody())); 1618 return lambda; 1619 } 1620 1621 @Override 1622 public DetailAstImpl visitSingleLambdaParam(JavaLanguageParser.SingleLambdaParamContext ctx) { 1623 return flattenedTree(ctx); 1624 } 1625 1626 @Override 1627 public DetailAstImpl visitFormalLambdaParam(JavaLanguageParser.FormalLambdaParamContext ctx) { 1628 final DetailAstImpl lparen = create(ctx.LPAREN()); 1629 1630 // We add an 'PARAMETERS' node here whether it exists or not 1631 final DetailAstImpl parameters = Optional.ofNullable(visit(ctx.formalParameterList())) 1632 .orElse(createImaginary(TokenTypes.PARAMETERS)); 1633 addLastSibling(lparen, parameters); 1634 addLastSibling(lparen, create(ctx.RPAREN())); 1635 return lparen; 1636 } 1637 1638 @Override 1639 public DetailAstImpl visitMultiLambdaParam(JavaLanguageParser.MultiLambdaParamContext ctx) { 1640 final DetailAstImpl lparen = create(ctx.LPAREN()); 1641 addLastSibling(lparen, visit(ctx.multiLambdaParams())); 1642 addLastSibling(lparen, create(ctx.RPAREN())); 1643 return lparen; 1644 } 1645 1646 @Override 1647 public DetailAstImpl visitMultiLambdaParams(JavaLanguageParser.MultiLambdaParamsContext ctx) { 1648 final DetailAstImpl parameters = createImaginary(TokenTypes.PARAMETERS); 1649 parameters.addChild(createLambdaParameter(ctx.id(0))); 1650 1651 for (int i = 0; i < ctx.COMMA().size(); i++) { 1652 parameters.addChild(create(ctx.COMMA(i))); 1653 parameters.addChild(createLambdaParameter(ctx.id(i + 1))); 1654 } 1655 return parameters; 1656 } 1657 1658 /** 1659 * Creates a 'PARAMETER_DEF' node for a lambda expression, with 1660 * imaginary modifier and type nodes. 1661 * 1662 * @param ctx the IdContext to create imaginary nodes for 1663 * @return DetailAstImpl of lambda parameter 1664 */ 1665 private DetailAstImpl createLambdaParameter(JavaLanguageParser.IdContext ctx) { 1666 final DetailAstImpl ident = visitId(ctx); 1667 final DetailAstImpl parameter = createImaginary(TokenTypes.PARAMETER_DEF); 1668 final DetailAstImpl modifiers = createImaginary(TokenTypes.MODIFIERS); 1669 final DetailAstImpl type = createImaginary(TokenTypes.TYPE); 1670 parameter.addChild(modifiers); 1671 parameter.addChild(type); 1672 parameter.addChild(ident); 1673 return parameter; 1674 } 1675 1676 @Override 1677 public DetailAstImpl visitParenPrimary(JavaLanguageParser.ParenPrimaryContext ctx) { 1678 return flattenedTree(ctx); 1679 } 1680 1681 @Override 1682 public DetailAstImpl visitTokenPrimary(JavaLanguageParser.TokenPrimaryContext ctx) { 1683 return flattenedTree(ctx); 1684 } 1685 1686 @Override 1687 public DetailAstImpl visitClassRefPrimary(JavaLanguageParser.ClassRefPrimaryContext ctx) { 1688 final DetailAstImpl dot = create(ctx.DOT()); 1689 final DetailAstImpl primaryTypeNoArray = visit(ctx.type); 1690 dot.addChild(primaryTypeNoArray); 1691 if (TokenUtil.isOfType(primaryTypeNoArray, TokenTypes.DOT)) { 1692 // We append '[]' to the qualified name 'TYPE' `ast 1693 ctx.arrayDeclarator() 1694 .forEach(child -> primaryTypeNoArray.addChild(visit(child))); 1695 } 1696 else { 1697 ctx.arrayDeclarator() 1698 .forEach(child -> addLastSibling(primaryTypeNoArray, visit(child))); 1699 } 1700 dot.addChild(create(ctx.LITERAL_CLASS())); 1701 return dot; 1702 } 1703 1704 @Override 1705 public DetailAstImpl visitPrimitivePrimary(JavaLanguageParser.PrimitivePrimaryContext ctx) { 1706 final DetailAstImpl dot = create(ctx.DOT()); 1707 final DetailAstImpl primaryTypeNoArray = visit(ctx.type); 1708 dot.addChild(primaryTypeNoArray); 1709 ctx.arrayDeclarator().forEach(child -> dot.addChild(visit(child))); 1710 dot.addChild(create(ctx.LITERAL_CLASS())); 1711 return dot; 1712 } 1713 1714 @Override 1715 public DetailAstImpl visitCreator(JavaLanguageParser.CreatorContext ctx) { 1716 return flattenedTree(ctx); 1717 } 1718 1719 @Override 1720 public DetailAstImpl visitCreatedNameObject(JavaLanguageParser.CreatedNameObjectContext ctx) { 1721 final DetailAstPair currentAST = new DetailAstPair(); 1722 DetailAstPair.addAstChild(currentAST, visit(ctx.annotations())); 1723 DetailAstPair.addAstChild(currentAST, visit(ctx.id())); 1724 DetailAstPair.addAstChild(currentAST, visit(ctx.typeArgumentsOrDiamond())); 1725 1726 // This is how we build the type arguments/ qualified name tree 1727 for (int i = 0; i < ctx.extended.size(); i++) { 1728 final ParserRuleContext extendedContext = ctx.extended.get(i); 1729 final DetailAstImpl dot = create(extendedContext.start); 1730 DetailAstPair.makeAstRoot(currentAST, dot); 1731 final List<ParseTree> childList = extendedContext 1732 .children.subList(1, extendedContext.children.size()); 1733 processChildren(dot, childList); 1734 } 1735 1736 return currentAST.root; 1737 } 1738 1739 @Override 1740 public DetailAstImpl visitCreatedNamePrimitive( 1741 JavaLanguageParser.CreatedNamePrimitiveContext ctx) { 1742 return flattenedTree(ctx); 1743 } 1744 1745 @Override 1746 public DetailAstImpl visitInnerCreator(JavaLanguageParser.InnerCreatorContext ctx) { 1747 return flattenedTree(ctx); 1748 } 1749 1750 @Override 1751 public DetailAstImpl visitArrayCreatorRest(JavaLanguageParser.ArrayCreatorRestContext ctx) { 1752 final DetailAstImpl arrayDeclarator = create(TokenTypes.ARRAY_DECLARATOR, 1753 (Token) ctx.LBRACK().getPayload()); 1754 // child[0] is LBRACK 1755 for (int i = 1; i < ctx.children.size(); i++) { 1756 if (ctx.children.get(i) == ctx.RBRACK()) { 1757 arrayDeclarator.addChild(create(ctx.RBRACK())); 1758 } 1759 else if (ctx.children.get(i) == ctx.expression()) { 1760 // Handle '[8]', etc. 1761 arrayDeclarator.addChild(visit(ctx.expression())); 1762 } 1763 else { 1764 addLastSibling(arrayDeclarator, visit(ctx.children.get(i))); 1765 } 1766 } 1767 return arrayDeclarator; 1768 } 1769 1770 @Override 1771 public DetailAstImpl visitBracketsWithExp(JavaLanguageParser.BracketsWithExpContext ctx) { 1772 final DetailAstImpl dummyRoot = new DetailAstImpl(); 1773 dummyRoot.addChild(visit(ctx.annotations())); 1774 final DetailAstImpl arrayDeclarator = 1775 create(TokenTypes.ARRAY_DECLARATOR, (Token) ctx.LBRACK().getPayload()); 1776 arrayDeclarator.addChild(visit(ctx.expression())); 1777 arrayDeclarator.addChild(create(ctx.stop)); 1778 dummyRoot.addChild(arrayDeclarator); 1779 return dummyRoot.getFirstChild(); 1780 } 1781 1782 @Override 1783 public DetailAstImpl visitClassCreatorRest(JavaLanguageParser.ClassCreatorRestContext ctx) { 1784 return flattenedTree(ctx); 1785 } 1786 1787 @Override 1788 public DetailAstImpl visitDiamond(JavaLanguageParser.DiamondContext ctx) { 1789 final DetailAstImpl typeArguments = 1790 createImaginary(TokenTypes.TYPE_ARGUMENTS); 1791 typeArguments.addChild(create(TokenTypes.GENERIC_START, 1792 (Token) ctx.LT().getPayload())); 1793 typeArguments.addChild(create(TokenTypes.GENERIC_END, 1794 (Token) ctx.GT().getPayload())); 1795 return typeArguments; 1796 } 1797 1798 @Override 1799 public DetailAstImpl visitTypeArgs(JavaLanguageParser.TypeArgsContext ctx) { 1800 return flattenedTree(ctx); 1801 } 1802 1803 @Override 1804 public DetailAstImpl visitNonWildcardDiamond( 1805 JavaLanguageParser.NonWildcardDiamondContext ctx) { 1806 final DetailAstImpl typeArguments = 1807 createImaginary(TokenTypes.TYPE_ARGUMENTS); 1808 typeArguments.addChild(create(TokenTypes.GENERIC_START, 1809 (Token) ctx.LT().getPayload())); 1810 typeArguments.addChild(create(TokenTypes.GENERIC_END, 1811 (Token) ctx.GT().getPayload())); 1812 return typeArguments; 1813 } 1814 1815 @Override 1816 public DetailAstImpl visitNonWildcardTypeArguments( 1817 JavaLanguageParser.NonWildcardTypeArgumentsContext ctx) { 1818 final DetailAstImpl typeArguments = createImaginary(TokenTypes.TYPE_ARGUMENTS); 1819 typeArguments.addChild(create(TokenTypes.GENERIC_START, (Token) ctx.LT().getPayload())); 1820 typeArguments.addChild(visit(ctx.typeArgumentsTypeList())); 1821 typeArguments.addChild(create(TokenTypes.GENERIC_END, (Token) ctx.GT().getPayload())); 1822 return typeArguments; 1823 } 1824 1825 @Override 1826 public DetailAstImpl visitTypeArgumentsTypeList( 1827 JavaLanguageParser.TypeArgumentsTypeListContext ctx) { 1828 final DetailAstImpl firstIdent = visit(ctx.typeType(0)); 1829 final DetailAstImpl firstTypeArgument = createImaginary(TokenTypes.TYPE_ARGUMENT); 1830 firstTypeArgument.addChild(firstIdent); 1831 1832 for (int i = 0; i < ctx.COMMA().size(); i++) { 1833 addLastSibling(firstTypeArgument, create(ctx.COMMA(i))); 1834 final DetailAstImpl ident = visit(ctx.typeType(i + 1)); 1835 final DetailAstImpl typeArgument = createImaginary(TokenTypes.TYPE_ARGUMENT); 1836 typeArgument.addChild(ident); 1837 addLastSibling(firstTypeArgument, typeArgument); 1838 } 1839 return firstTypeArgument; 1840 } 1841 1842 @Override 1843 public DetailAstImpl visitTypeList(JavaLanguageParser.TypeListContext ctx) { 1844 return flattenedTree(ctx); 1845 } 1846 1847 @Override 1848 public DetailAstImpl visitTypeType(JavaLanguageParser.TypeTypeContext ctx) { 1849 final DetailAstImpl type = createImaginary(TokenTypes.TYPE); 1850 processChildren(type, ctx.children); 1851 1852 final DetailAstImpl returnTree; 1853 if (ctx.createImaginaryNode) { 1854 returnTree = type; 1855 } 1856 else { 1857 returnTree = type.getFirstChild(); 1858 } 1859 return returnTree; 1860 } 1861 1862 @Override 1863 public DetailAstImpl visitArrayDeclarator(JavaLanguageParser.ArrayDeclaratorContext ctx) { 1864 final DetailAstImpl arrayDeclarator = create(TokenTypes.ARRAY_DECLARATOR, 1865 (Token) ctx.LBRACK().getPayload()); 1866 arrayDeclarator.addChild(create(ctx.RBRACK())); 1867 1868 final DetailAstImpl returnTree; 1869 final DetailAstImpl annotations = visit(ctx.anno); 1870 if (annotations == null) { 1871 returnTree = arrayDeclarator; 1872 } 1873 else { 1874 returnTree = annotations; 1875 addLastSibling(returnTree, arrayDeclarator); 1876 } 1877 return returnTree; 1878 } 1879 1880 @Override 1881 public DetailAstImpl visitPrimitiveType(JavaLanguageParser.PrimitiveTypeContext ctx) { 1882 return create(ctx.start); 1883 } 1884 1885 @Override 1886 public DetailAstImpl visitTypeArguments(JavaLanguageParser.TypeArgumentsContext ctx) { 1887 final DetailAstImpl typeArguments = createImaginary(TokenTypes.TYPE_ARGUMENTS); 1888 typeArguments.addChild(create(TokenTypes.GENERIC_START, (Token) ctx.LT().getPayload())); 1889 // Exclude '<' and '>' 1890 processChildren(typeArguments, ctx.children.subList(1, ctx.children.size() - 1)); 1891 typeArguments.addChild(create(TokenTypes.GENERIC_END, (Token) ctx.GT().getPayload())); 1892 return typeArguments; 1893 } 1894 1895 @Override 1896 public DetailAstImpl visitSuperSuffixDot(JavaLanguageParser.SuperSuffixDotContext ctx) { 1897 final DetailAstImpl root; 1898 if (ctx.LPAREN() == null) { 1899 root = create(ctx.DOT()); 1900 root.addChild(visit(ctx.id())); 1901 } 1902 else { 1903 root = create(TokenTypes.METHOD_CALL, (Token) ctx.LPAREN().getPayload()); 1904 1905 final DetailAstImpl dot = create(ctx.DOT()); 1906 dot.addChild(visit(ctx.id())); 1907 root.addChild(dot); 1908 1909 final DetailAstImpl expressionList = Optional.ofNullable(visit(ctx.expressionList())) 1910 .orElse(createImaginary(TokenTypes.ELIST)); 1911 root.addChild(expressionList); 1912 1913 root.addChild(create(ctx.RPAREN())); 1914 } 1915 1916 return root; 1917 } 1918 1919 @Override 1920 public DetailAstImpl visitArguments(JavaLanguageParser.ArgumentsContext ctx) { 1921 final DetailAstImpl lparen = create(ctx.LPAREN()); 1922 1923 // We always add an 'ELIST' node 1924 final DetailAstImpl expressionList = Optional.ofNullable(visit(ctx.expressionList())) 1925 .orElse(createImaginary(TokenTypes.ELIST)); 1926 addLastSibling(lparen, expressionList); 1927 addLastSibling(lparen, create(ctx.RPAREN())); 1928 return lparen; 1929 } 1930 1931 @Override 1932 public DetailAstImpl visitPatternVariableDefinition( 1933 JavaLanguageParser.PatternVariableDefinitionContext ctx) { 1934 final DetailAstImpl type = visit(ctx.type); 1935 final DetailAstImpl patternVariableDef = createImaginary(TokenTypes.PATTERN_VARIABLE_DEF); 1936 patternVariableDef.addChild(createModifiers(ctx.mods)); 1937 patternVariableDef.addChild(type); 1938 patternVariableDef.addChild(visit(ctx.id())); 1939 return patternVariableDef; 1940 } 1941 1942 @Override 1943 public DetailAstImpl visitPermittedSubclassesAndInterfaces( 1944 JavaLanguageParser.PermittedSubclassesAndInterfacesContext ctx) { 1945 final DetailAstImpl literalPermits = 1946 create(TokenTypes.PERMITS_CLAUSE, (Token) ctx.LITERAL_PERMITS().getPayload()); 1947 // 'LITERAL_PERMITS' is child[0] 1948 processChildren(literalPermits, ctx.children.subList(1, ctx.children.size())); 1949 return literalPermits; 1950 } 1951 1952 @Override 1953 public DetailAstImpl visitId(JavaLanguageParser.IdContext ctx) { 1954 return create(TokenTypes.IDENT, ctx.start); 1955 } 1956 1957 /** 1958 * Builds the AST for a particular node, then returns a "flattened" tree 1959 * of siblings. This method should be used in rule contexts such as 1960 * {@code variableDeclarators}, where we have both terminals and non-terminals. 1961 * 1962 * @param ctx the ParserRuleContext to base tree on 1963 * @return flattened DetailAstImpl 1964 */ 1965 private DetailAstImpl flattenedTree(ParserRuleContext ctx) { 1966 final DetailAstImpl dummyNode = new DetailAstImpl(); 1967 processChildren(dummyNode, ctx.children); 1968 return dummyNode.getFirstChild(); 1969 } 1970 1971 /** 1972 * Adds all the children from the given ParseTree or JavaParserContext 1973 * list to the parent DetailAstImpl. 1974 * 1975 * @param parent the DetailAstImpl to add children to 1976 * @param children the list of children to add 1977 */ 1978 private void processChildren(DetailAstImpl parent, List<? extends ParseTree> children) { 1979 children.forEach(child -> { 1980 if (child instanceof TerminalNode) { 1981 // Child is a token, create a new DetailAstImpl and add it to parent 1982 parent.addChild(create((TerminalNode) child)); 1983 } 1984 else { 1985 // Child is another rule context; visit it, create token, and add to parent 1986 parent.addChild(visit(child)); 1987 } 1988 }); 1989 } 1990 1991 /** 1992 * Create a DetailAstImpl from a given token and token type. This method 1993 * should be used for imaginary nodes only, i.e. 'OBJBLOCK -> OBJBLOCK', 1994 * where the text on the RHS matches the text on the LHS. 1995 * 1996 * @param tokenType the token type of this DetailAstImpl 1997 * @return new DetailAstImpl of given type 1998 */ 1999 private static DetailAstImpl createImaginary(int tokenType) { 2000 final DetailAstImpl detailAst = new DetailAstImpl(); 2001 detailAst.setType(tokenType); 2002 detailAst.setText(TokenUtil.getTokenName(tokenType)); 2003 return detailAst; 2004 } 2005 2006 /** 2007 * Create a DetailAstImpl from a given token and token type. This method 2008 * should be used for literal nodes only, i.e. 'PACKAGE_DEF -> package'. 2009 * 2010 * @param tokenType the token type of this DetailAstImpl 2011 * @param startToken the first token that appears in this DetailAstImpl. 2012 * @return new DetailAstImpl of given type 2013 */ 2014 private DetailAstImpl create(int tokenType, Token startToken) { 2015 final DetailAstImpl ast = create(startToken); 2016 ast.setType(tokenType); 2017 return ast; 2018 } 2019 2020 /** 2021 * Create a DetailAstImpl from a given token. This method should be 2022 * used for terminal nodes, i.e. {@code LCURLY}, when we are building 2023 * an AST for a specific token, regardless of position. 2024 * 2025 * @param token the token to build the DetailAstImpl from 2026 * @return new DetailAstImpl of given type 2027 */ 2028 private DetailAstImpl create(Token token) { 2029 final int tokenIndex = token.getTokenIndex(); 2030 final List<Token> tokensToLeft = 2031 tokens.getHiddenTokensToLeft(tokenIndex, JavaLanguageLexer.COMMENTS); 2032 final List<Token> tokensToRight = 2033 tokens.getHiddenTokensToRight(tokenIndex, JavaLanguageLexer.COMMENTS); 2034 2035 final DetailAstImpl detailAst = new DetailAstImpl(); 2036 detailAst.initialize(token); 2037 if (tokensToLeft != null) { 2038 detailAst.setHiddenBefore(tokensToLeft); 2039 } 2040 if (tokensToRight != null) { 2041 detailAst.setHiddenAfter(tokensToRight); 2042 } 2043 return detailAst; 2044 } 2045 2046 /** 2047 * Create a DetailAstImpl from a given TerminalNode. This method should be 2048 * used for terminal nodes, i.e. {@code @}. 2049 * 2050 * @param node the TerminalNode to build the DetailAstImpl from 2051 * @return new DetailAstImpl of given type 2052 */ 2053 private DetailAstImpl create(TerminalNode node) { 2054 return create((Token) node.getPayload()); 2055 } 2056 2057 /** 2058 * Creates a type declaration DetailAstImpl from a given rule context. 2059 * 2060 * @param ctx ParserRuleContext we are in 2061 * @param type the type declaration to create 2062 * @param modifierList respective modifiers 2063 * @return type declaration DetailAstImpl 2064 */ 2065 private DetailAstImpl createTypeDeclaration(ParserRuleContext ctx, int type, 2066 List<? extends ParseTree> modifierList) { 2067 final DetailAstImpl typeDeclaration = createImaginary(type); 2068 typeDeclaration.addChild(createModifiers(modifierList)); 2069 processChildren(typeDeclaration, ctx.children); 2070 return typeDeclaration; 2071 } 2072 2073 /** 2074 * Builds the modifiers AST. 2075 * 2076 * @param modifierList the list of modifier contexts 2077 * @return "MODIFIERS" ast 2078 */ 2079 private DetailAstImpl createModifiers(List<? extends ParseTree> modifierList) { 2080 final DetailAstImpl mods = createImaginary(TokenTypes.MODIFIERS); 2081 processChildren(mods, modifierList); 2082 return mods; 2083 } 2084 2085 /** 2086 * Add new sibling to the end of existing siblings. 2087 * 2088 * @param self DetailAstImpl to add last sibling to 2089 * @param sibling DetailAstImpl sibling to add 2090 */ 2091 private static void addLastSibling(DetailAstImpl self, DetailAstImpl sibling) { 2092 DetailAstImpl nextSibling = self; 2093 if (nextSibling != null) { 2094 while (nextSibling.getNextSibling() != null) { 2095 nextSibling = nextSibling.getNextSibling(); 2096 } 2097 nextSibling.setNextSibling(sibling); 2098 } 2099 } 2100 2101 @Override 2102 public DetailAstImpl visit(ParseTree tree) { 2103 DetailAstImpl ast = null; 2104 if (tree != null) { 2105 ast = tree.accept(this); 2106 } 2107 return ast; 2108 } 2109 2110 /** 2111 * Used to swap and organize DetailAstImpl subtrees. 2112 */ 2113 private static final class DetailAstPair { 2114 2115 /** The root DetailAstImpl of this pair. */ 2116 private DetailAstImpl root; 2117 2118 /** The child (potentially with siblings) of this pair. */ 2119 private DetailAstImpl child; 2120 2121 /** 2122 * Moves child reference to the last child. 2123 */ 2124 private void advanceChildToEnd() { 2125 while (child.getNextSibling() != null) { 2126 child = child.getNextSibling(); 2127 } 2128 } 2129 2130 /** 2131 * Returns the root node. 2132 * 2133 * @return the root node 2134 */ 2135 private DetailAstImpl getRoot() { 2136 return root; 2137 } 2138 2139 /** 2140 * This method is used to replace the {@code ^} (set as root node) ANTLR2 2141 * operator. 2142 * 2143 * @param pair the DetailAstPair to use for swapping nodes 2144 * @param ast the new root 2145 */ 2146 private static void makeAstRoot(DetailAstPair pair, DetailAstImpl ast) { 2147 ast.addChild(pair.root); 2148 pair.child = pair.root; 2149 pair.advanceChildToEnd(); 2150 pair.root = ast; 2151 } 2152 2153 /** 2154 * Adds a child (or new root) to the given DetailAstPair. 2155 * 2156 * @param pair the DetailAstPair to add child to 2157 * @param ast the child to add 2158 */ 2159 private static void addAstChild(DetailAstPair pair, DetailAstImpl ast) { 2160 if (ast != null) { 2161 if (pair.root == null) { 2162 pair.root = ast; 2163 } 2164 else { 2165 pair.child.setNextSibling(ast); 2166 } 2167 pair.child = ast; 2168 pair.advanceChildToEnd(); 2169 } 2170 } 2171 } 2172}