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