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