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