001////////////////////////////////////////////////////////////////////////////////
002// checkstyle: Checks Java source code for adherence to a set of rules.
003// Copyright (C) 2001-2021 the original author or authors.
004//
005// This library is free software; you can redistribute it and/or
006// modify it under the terms of the GNU Lesser General Public
007// License as published by the Free Software Foundation; either
008// version 2.1 of the License, or (at your option) any later version.
009//
010// This library is distributed in the hope that it will be useful,
011// but WITHOUT ANY WARRANTY; without even the implied warranty of
012// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
013// Lesser General Public License for more details.
014//
015// You should have received a copy of the GNU Lesser General Public
016// License along with this library; if not, write to the Free Software
017// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
018////////////////////////////////////////////////////////////////////////////////
019
020package com.puppycrawl.tools.checkstyle;
021
022import java.util.ArrayList;
023import java.util.Collections;
024import java.util.Iterator;
025import java.util.List;
026import java.util.Optional;
027import java.util.Queue;
028import java.util.concurrent.ConcurrentLinkedQueue;
029import java.util.stream.Collectors;
030
031import org.antlr.v4.runtime.BufferedTokenStream;
032import org.antlr.v4.runtime.CommonTokenStream;
033import org.antlr.v4.runtime.ParserRuleContext;
034import org.antlr.v4.runtime.Token;
035import org.antlr.v4.runtime.tree.ParseTree;
036import org.antlr.v4.runtime.tree.TerminalNode;
037
038import com.puppycrawl.tools.checkstyle.api.TokenTypes;
039import com.puppycrawl.tools.checkstyle.grammar.java.JavaLanguageLexer;
040import com.puppycrawl.tools.checkstyle.grammar.java.JavaLanguageParser;
041import com.puppycrawl.tools.checkstyle.grammar.java.JavaLanguageParserBaseVisitor;
042import com.puppycrawl.tools.checkstyle.utils.TokenUtil;
043
044/**
045 * Visitor class used to build Checkstyle's Java AST from the parse tree produced by
046 * {@link JavaLanguageParser}. In each {@code visit...} method, we visit the children of a node
047 * (which correspond to subrules) or create terminal nodes (tokens), and return a subtree as a
048 * result.
049 *
050 * <p>Example:</p>
051 *
052 * <p>The following package declaration:</p>
053 * <pre>
054 * package com.puppycrawl.tools.checkstyle;
055 * </pre>
056 *
057 * <p>
058 * Will be parsed by the {@code packageDeclaration} rule from {@code JavaLanguageParser.g4}:
059 * </p>
060 * <pre>
061 * packageDeclaration
062 *     : annotations[true] LITERAL_PACKAGE qualifiedName SEMI
063 *     ;
064 * </pre>
065 *
066 * <p>
067 * We override the {@code visitPackageDeclaration} method generated by ANTLR in
068 * {@link JavaLanguageParser} at
069 * {@link JavaAstVisitor#visitPackageDeclaration(JavaLanguageParser.PackageDeclarationContext)}
070 * to create a subtree based on the subrules and tokens found in the {@code packageDeclaration}
071 * subrule accordingly, thus producing the following AST:
072 * </p>
073 * <pre>
074 * PACKAGE_DEF -&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 (int i = 0; i < ctx.extended.size(); i++) {
556            final ParserRuleContext extendedContext = ctx.extended.get(i);
557            final DetailAstImpl dot = create(extendedContext.start);
558            DetailAstPair.makeAstRoot(currentAST, dot);
559            final List<ParseTree> childList = extendedContext
560                    .children.subList(1, extendedContext.children.size());
561            childList.forEach(child -> DetailAstPair.addAstChild(currentAST, visit(child)));
562        }
563
564        // Create imaginary 'TYPE' parent if specified
565        final DetailAstImpl returnTree;
566        if (ctx.createImaginaryNode) {
567            returnTree = createImaginary(TokenTypes.TYPE);
568            returnTree.addChild(currentAST.root);
569        }
570        else {
571            returnTree = currentAST.root;
572        }
573        return returnTree;
574    }
575
576    @Override
577    public DetailAstImpl visitSimpleTypeArgument(
578            JavaLanguageParser.SimpleTypeArgumentContext ctx) {
579        final DetailAstImpl typeArgument =
580                createImaginary(TokenTypes.TYPE_ARGUMENT);
581        typeArgument.addChild(visit(ctx.typeType()));
582        return typeArgument;
583    }
584
585    @Override
586    public DetailAstImpl visitWildCardTypeArgument(
587            JavaLanguageParser.WildCardTypeArgumentContext ctx) {
588        final DetailAstImpl typeArgument = createImaginary(TokenTypes.TYPE_ARGUMENT);
589        typeArgument.addChild(visit(ctx.annotations()));
590        typeArgument.addChild(create(TokenTypes.WILDCARD_TYPE,
591                (Token) ctx.QUESTION().getPayload()));
592
593        if (ctx.upperBound != null) {
594            final DetailAstImpl upperBound = create(TokenTypes.TYPE_UPPER_BOUNDS, ctx.upperBound);
595            upperBound.addChild(visit(ctx.typeType()));
596            typeArgument.addChild(upperBound);
597        }
598        else if (ctx.lowerBound != null) {
599            final DetailAstImpl lowerBound = create(TokenTypes.TYPE_LOWER_BOUNDS, ctx.lowerBound);
600            lowerBound.addChild(visit(ctx.typeType()));
601            typeArgument.addChild(lowerBound);
602        }
603
604        return typeArgument;
605    }
606
607    @Override
608    public DetailAstImpl visitQualifiedNameList(JavaLanguageParser.QualifiedNameListContext ctx) {
609        return flattenedTree(ctx);
610    }
611
612    @Override
613    public DetailAstImpl visitFormalParameters(JavaLanguageParser.FormalParametersContext ctx) {
614        final DetailAstImpl lparen = create(ctx.LPAREN());
615
616        // We make a "PARAMETERS" node whether parameters exist or not
617        if (ctx.formalParameterList() == null) {
618            addLastSibling(lparen, createImaginary(TokenTypes.PARAMETERS));
619        }
620        else {
621            addLastSibling(lparen, visit(ctx.formalParameterList()));
622        }
623        addLastSibling(lparen, create(ctx.RPAREN()));
624        return lparen;
625    }
626
627    @Override
628    public DetailAstImpl visitFormalParameterList(
629            JavaLanguageParser.FormalParameterListContext ctx) {
630        final DetailAstImpl parameters = createImaginary(TokenTypes.PARAMETERS);
631        processChildren(parameters, ctx.children);
632        return parameters;
633    }
634
635    @Override
636    public DetailAstImpl visitFormalParameter(JavaLanguageParser.FormalParameterContext ctx) {
637        final DetailAstImpl variableDeclaratorId =
638                visitVariableDeclaratorId(ctx.variableDeclaratorId());
639        final DetailAstImpl parameterDef = createImaginary(TokenTypes.PARAMETER_DEF);
640        parameterDef.addChild(variableDeclaratorId);
641        return parameterDef;
642    }
643
644    @Override
645    public DetailAstImpl visitLastFormalParameter(
646            JavaLanguageParser.LastFormalParameterContext ctx) {
647        final DetailAstImpl parameterDef =
648                createImaginary(TokenTypes.PARAMETER_DEF);
649        parameterDef.addChild(visit(ctx.variableDeclaratorId()));
650        final DetailAstImpl ident = (DetailAstImpl) parameterDef.findFirstToken(TokenTypes.IDENT);
651        ident.addPreviousSibling(create(ctx.ELLIPSIS()));
652        // We attach annotations on ellipses in varargs to the 'TYPE' ast
653        final DetailAstImpl type = (DetailAstImpl) parameterDef.findFirstToken(TokenTypes.TYPE);
654        type.addChild(visit(ctx.annotations()));
655        return parameterDef;
656    }
657
658    @Override
659    public DetailAstImpl visitQualifiedName(JavaLanguageParser.QualifiedNameContext ctx) {
660        final DetailAstImpl ast = visit(ctx.id());
661        final DetailAstPair currentAst = new DetailAstPair();
662        DetailAstPair.addAstChild(currentAst, ast);
663
664        for (int i = 0; i < ctx.extended.size(); i++) {
665            final ParserRuleContext extendedContext = ctx.extended.get(i);
666            final DetailAstImpl dot = create(extendedContext.start);
667            DetailAstPair.makeAstRoot(currentAst, dot);
668            final List<ParseTree> childList = extendedContext
669                    .children.subList(1, extendedContext.children.size());
670            processChildren(dot, childList);
671        }
672        return currentAst.getRoot();
673    }
674
675    @Override
676    public DetailAstImpl visitLiteral(JavaLanguageParser.LiteralContext ctx) {
677        return flattenedTree(ctx);
678    }
679
680    @Override
681    public DetailAstImpl visitIntegerLiteral(JavaLanguageParser.IntegerLiteralContext ctx) {
682        final int[] longTypes = {
683            JavaLanguageLexer.DECIMAL_LITERAL_LONG,
684            JavaLanguageLexer.HEX_LITERAL_LONG,
685            JavaLanguageLexer.OCT_LITERAL_LONG,
686            JavaLanguageLexer.BINARY_LITERAL_LONG,
687        };
688
689        final int tokenType;
690        if (TokenUtil.isOfType(ctx.start.getType(), longTypes)) {
691            tokenType = TokenTypes.NUM_LONG;
692        }
693        else {
694            tokenType = TokenTypes.NUM_INT;
695        }
696
697        return create(tokenType, ctx.start);
698    }
699
700    @Override
701    public DetailAstImpl visitFloatLiteral(JavaLanguageParser.FloatLiteralContext ctx) {
702        final DetailAstImpl floatLiteral;
703        if (TokenUtil.isOfType(ctx.start.getType(),
704                JavaLanguageLexer.DOUBLE_LITERAL, JavaLanguageLexer.HEX_DOUBLE_LITERAL)) {
705            floatLiteral = create(TokenTypes.NUM_DOUBLE, ctx.start);
706        }
707        else {
708            floatLiteral = create(TokenTypes.NUM_FLOAT, ctx.start);
709        }
710        return floatLiteral;
711    }
712
713    @Override
714    public DetailAstImpl visitTextBlockLiteral(JavaLanguageParser.TextBlockLiteralContext ctx) {
715        final DetailAstImpl textBlockLiteralBegin = create(ctx.TEXT_BLOCK_LITERAL_BEGIN());
716        textBlockLiteralBegin.addChild(create(ctx.TEXT_BLOCK_CONTENT()));
717        textBlockLiteralBegin.addChild(create(ctx.TEXT_BLOCK_LITERAL_END()));
718        return textBlockLiteralBegin;
719    }
720
721    @Override
722    public DetailAstImpl visitAnnotations(JavaLanguageParser.AnnotationsContext ctx) {
723        final DetailAstImpl annotations;
724
725        if (!ctx.createImaginaryNode && ctx.anno.isEmpty()) {
726            // There are no annotations, and we don't want to create the empty node
727            annotations = null;
728        }
729        else {
730            // There are annotations, or we just want the empty node
731            annotations = createImaginary(TokenTypes.ANNOTATIONS);
732            processChildren(annotations, ctx.anno);
733        }
734
735        return annotations;
736    }
737
738    @Override
739    public DetailAstImpl visitAnnotation(JavaLanguageParser.AnnotationContext ctx) {
740        final DetailAstImpl annotation = createImaginary(TokenTypes.ANNOTATION);
741        processChildren(annotation, ctx.children);
742        return annotation;
743    }
744
745    @Override
746    public DetailAstImpl visitElementValuePairs(JavaLanguageParser.ElementValuePairsContext ctx) {
747        return flattenedTree(ctx);
748    }
749
750    @Override
751    public DetailAstImpl visitElementValuePair(JavaLanguageParser.ElementValuePairContext ctx) {
752        final DetailAstImpl elementValuePair =
753                createImaginary(TokenTypes.ANNOTATION_MEMBER_VALUE_PAIR);
754        processChildren(elementValuePair, ctx.children);
755        return elementValuePair;
756    }
757
758    @Override
759    public DetailAstImpl visitElementValue(JavaLanguageParser.ElementValueContext ctx) {
760        return flattenedTree(ctx);
761    }
762
763    @Override
764    public DetailAstImpl visitElementValueArrayInitializer(
765            JavaLanguageParser.ElementValueArrayInitializerContext ctx) {
766        final DetailAstImpl arrayInit =
767                create(TokenTypes.ANNOTATION_ARRAY_INIT, (Token) ctx.LCURLY().getPayload());
768        processChildren(arrayInit, ctx.children.subList(1, ctx.children.size()));
769        return arrayInit;
770    }
771
772    @Override
773    public DetailAstImpl visitAnnotationTypeDeclaration(
774            JavaLanguageParser.AnnotationTypeDeclarationContext ctx) {
775        return createTypeDeclaration(ctx, TokenTypes.ANNOTATION_DEF, ctx.mods);
776    }
777
778    @Override
779    public DetailAstImpl visitAnnotationTypeBody(
780            JavaLanguageParser.AnnotationTypeBodyContext ctx) {
781        final DetailAstImpl objBlock = createImaginary(TokenTypes.OBJBLOCK);
782        processChildren(objBlock, ctx.children);
783        return objBlock;
784    }
785
786    @Override
787    public DetailAstImpl visitAnnotationTypeElementDeclaration(
788            JavaLanguageParser.AnnotationTypeElementDeclarationContext ctx) {
789        final DetailAstImpl returnTree;
790        if (ctx.SEMI() == null) {
791            returnTree = visit(ctx.annotationTypeElementRest());
792        }
793        else {
794            returnTree = create(ctx.SEMI());
795        }
796        return returnTree;
797    }
798
799    @Override
800    public DetailAstImpl visitAnnotationField(JavaLanguageParser.AnnotationFieldContext ctx) {
801        final DetailAstImpl dummyNode = new DetailAstImpl();
802        // Since the TYPE AST is built by visitAnnotationMethodOrConstantRest(), we skip it
803        // here (child [0])
804        processChildren(dummyNode, Collections.singletonList(ctx.children.get(1)));
805        // We also append the SEMI token to the first child [size() - 1],
806        // until https://github.com/checkstyle/checkstyle/issues/3151
807        dummyNode.getFirstChild().addChild(create(ctx.SEMI()));
808        return dummyNode.getFirstChild();
809    }
810
811    @Override
812    public DetailAstImpl visitAnnotationType(JavaLanguageParser.AnnotationTypeContext ctx) {
813        return flattenedTree(ctx);
814    }
815
816    @Override
817    public DetailAstImpl visitAnnotationMethodRest(
818            JavaLanguageParser.AnnotationMethodRestContext ctx) {
819        final DetailAstImpl annotationFieldDef =
820                createImaginary(TokenTypes.ANNOTATION_FIELD_DEF);
821        annotationFieldDef.addChild(createModifiers(ctx.mods));
822        annotationFieldDef.addChild(visit(ctx.type));
823
824        // Process all children except C style array declarators
825        processChildren(annotationFieldDef, ctx.children.stream()
826                .filter(child -> !(child instanceof JavaLanguageParser.ArrayDeclaratorContext))
827                .collect(Collectors.toList()));
828
829        // We add C style array declarator brackets to TYPE ast
830        final DetailAstImpl typeAst =
831                (DetailAstImpl) annotationFieldDef.findFirstToken(TokenTypes.TYPE);
832        ctx.cStyleArrDec.forEach(child -> typeAst.addChild(visit(child)));
833
834        return annotationFieldDef;
835    }
836
837    @Override
838    public DetailAstImpl visitDefaultValue(JavaLanguageParser.DefaultValueContext ctx) {
839        final DetailAstImpl defaultValue = create(ctx.LITERAL_DEFAULT());
840        defaultValue.addChild(visit(ctx.elementValue()));
841        return defaultValue;
842    }
843
844    @Override
845    public DetailAstImpl visitConstructorBlock(JavaLanguageParser.ConstructorBlockContext ctx) {
846        final DetailAstImpl slist = create(TokenTypes.SLIST, ctx.start);
847        // SLIST was child [0]
848        processChildren(slist, ctx.children.subList(1, ctx.children.size()));
849        return slist;
850    }
851
852    @Override
853    public DetailAstImpl visitExplicitCtorCall(JavaLanguageParser.ExplicitCtorCallContext ctx) {
854        final DetailAstImpl root;
855        if (ctx.LITERAL_THIS() == null) {
856            root = create(TokenTypes.SUPER_CTOR_CALL, (Token) ctx.LITERAL_SUPER().getPayload());
857        }
858        else {
859            root = create(TokenTypes.CTOR_CALL, (Token) ctx.LITERAL_THIS().getPayload());
860        }
861        root.addChild(visit(ctx.typeArguments()));
862        root.addChild(visit(ctx.arguments()));
863        root.addChild(create(ctx.SEMI()));
864        return root;
865    }
866
867    @Override
868    public DetailAstImpl visitPrimaryCtorCall(JavaLanguageParser.PrimaryCtorCallContext ctx) {
869        final DetailAstImpl primaryCtorCall = create(TokenTypes.SUPER_CTOR_CALL,
870                (Token) ctx.LITERAL_SUPER().getPayload());
871        // filter 'LITERAL_SUPER'
872        processChildren(primaryCtorCall, ctx.children.stream()
873                   .filter(child -> !child.equals(ctx.LITERAL_SUPER()))
874                   .collect(Collectors.toList()));
875        return primaryCtorCall;
876    }
877
878    @Override
879    public DetailAstImpl visitBlock(JavaLanguageParser.BlockContext ctx) {
880        final DetailAstImpl slist = create(TokenTypes.SLIST, ctx.start);
881        // SLIST was child [0]
882        processChildren(slist, ctx.children.subList(1, ctx.children.size()));
883        return slist;
884    }
885
886    @Override
887    public DetailAstImpl visitLocalVar(JavaLanguageParser.LocalVarContext ctx) {
888        return flattenedTree(ctx);
889    }
890
891    @Override
892    public DetailAstImpl visitBlockStat(JavaLanguageParser.BlockStatContext ctx) {
893        return flattenedTree(ctx);
894    }
895
896    @Override
897    public DetailAstImpl visitAssertExp(JavaLanguageParser.AssertExpContext ctx) {
898        final DetailAstImpl assertExp = create(ctx.ASSERT());
899        // child[0] is 'ASSERT'
900        processChildren(assertExp, ctx.children.subList(1, ctx.children.size()));
901        return assertExp;
902    }
903
904    @Override
905    public DetailAstImpl visitIfStat(JavaLanguageParser.IfStatContext ctx) {
906        final DetailAstImpl ifStat = create(ctx.LITERAL_IF());
907        // child[0] is 'LITERAL_IF'
908        processChildren(ifStat, ctx.children.subList(1, ctx.children.size()));
909        return ifStat;
910    }
911
912    @Override
913    public DetailAstImpl visitForStat(JavaLanguageParser.ForStatContext ctx) {
914        final DetailAstImpl forInit = create(ctx.start);
915        // child[0] is LITERAL_FOR
916        processChildren(forInit, ctx.children.subList(1, ctx.children.size()));
917        return forInit;
918    }
919
920    @Override
921    public DetailAstImpl visitWhileStat(JavaLanguageParser.WhileStatContext ctx) {
922        final DetailAstImpl whileStatement = create(ctx.start);
923        // 'LITERAL_WHILE' is child[0]
924        processChildren(whileStatement, ctx.children.subList(1, ctx.children.size()));
925        return whileStatement;
926    }
927
928    @Override
929    public DetailAstImpl visitDoStat(JavaLanguageParser.DoStatContext ctx) {
930        final DetailAstImpl doStatement = create(ctx.start);
931        // 'LITERAL_DO' is child[0]
932        doStatement.addChild(visit(ctx.statement()));
933        // We make 'LITERAL_WHILE' into 'DO_WHILE'
934        doStatement.addChild(create(TokenTypes.DO_WHILE, (Token) ctx.LITERAL_WHILE().getPayload()));
935        doStatement.addChild(visit(ctx.parExpression()));
936        doStatement.addChild(create(ctx.SEMI()));
937        return doStatement;
938    }
939
940    @Override
941    public DetailAstImpl visitTryStat(JavaLanguageParser.TryStatContext ctx) {
942        final DetailAstImpl tryStat = create(ctx.start);
943        // child[0] is 'LITERAL_TRY'
944        processChildren(tryStat, ctx.children.subList(1, ctx.children.size()));
945        return tryStat;
946    }
947
948    @Override
949    public DetailAstImpl visitTryWithResourceStat(
950            JavaLanguageParser.TryWithResourceStatContext ctx) {
951        final DetailAstImpl tryWithResources = create(ctx.LITERAL_TRY());
952        // child[0] is 'LITERAL_TRY'
953        processChildren(tryWithResources, ctx.children.subList(1, ctx.children.size()));
954        return tryWithResources;
955    }
956
957    @Override
958    public DetailAstImpl visitYieldStat(JavaLanguageParser.YieldStatContext ctx) {
959        final DetailAstImpl yieldParent = create(ctx.LITERAL_YIELD());
960        // LITERAL_YIELD is child[0]
961        processChildren(yieldParent, ctx.children.subList(1, ctx.children.size()));
962        return yieldParent;
963    }
964
965    @Override
966    public DetailAstImpl visitSyncStat(JavaLanguageParser.SyncStatContext ctx) {
967        final DetailAstImpl syncStatement = create(ctx.start);
968        // child[0] is 'LITERAL_SYNCHRONIZED'
969        processChildren(syncStatement, ctx.children.subList(1, ctx.children.size()));
970        return syncStatement;
971    }
972
973    @Override
974    public DetailAstImpl visitReturnStat(JavaLanguageParser.ReturnStatContext ctx) {
975        final DetailAstImpl returnStat = create(ctx.LITERAL_RETURN());
976        // child[0] is 'LITERAL_RETURN'
977        processChildren(returnStat, ctx.children.subList(1, ctx.children.size()));
978        return returnStat;
979    }
980
981    @Override
982    public DetailAstImpl visitThrowStat(JavaLanguageParser.ThrowStatContext ctx) {
983        final DetailAstImpl throwStat = create(ctx.LITERAL_THROW());
984        // child[0] is 'LITERAL_THROW'
985        processChildren(throwStat, ctx.children.subList(1, ctx.children.size()));
986        return throwStat;
987    }
988
989    @Override
990    public DetailAstImpl visitBreakStat(JavaLanguageParser.BreakStatContext ctx) {
991        final DetailAstImpl literalBreak = create(ctx.LITERAL_BREAK());
992        // child[0] is 'LITERAL_BREAK'
993        processChildren(literalBreak, ctx.children.subList(1, ctx.children.size()));
994        return literalBreak;
995    }
996
997    @Override
998    public DetailAstImpl visitContinueStat(JavaLanguageParser.ContinueStatContext ctx) {
999        final DetailAstImpl continueStat = create(ctx.LITERAL_CONTINUE());
1000        // child[0] is 'LITERAL_CONTINUE'
1001        processChildren(continueStat, ctx.children.subList(1, ctx.children.size()));
1002        return continueStat;
1003    }
1004
1005    @Override
1006    public DetailAstImpl visitEmptyStat(JavaLanguageParser.EmptyStatContext ctx) {
1007        return create(TokenTypes.EMPTY_STAT, ctx.start);
1008    }
1009
1010    @Override
1011    public DetailAstImpl visitExpStat(JavaLanguageParser.ExpStatContext ctx) {
1012        final DetailAstImpl expStatRoot = visit(ctx.statementExpression);
1013        addLastSibling(expStatRoot, create(ctx.SEMI()));
1014        return expStatRoot;
1015    }
1016
1017    @Override
1018    public DetailAstImpl visitLabelStat(JavaLanguageParser.LabelStatContext ctx) {
1019        final DetailAstImpl labelStat = create(TokenTypes.LABELED_STAT,
1020                (Token) ctx.COLON().getPayload());
1021        labelStat.addChild(visit(ctx.id()));
1022        labelStat.addChild(visit(ctx.statement()));
1023        return labelStat;
1024    }
1025
1026    @Override
1027    public DetailAstImpl visitSwitchExpressionOrStatement(
1028            JavaLanguageParser.SwitchExpressionOrStatementContext ctx) {
1029        final DetailAstImpl switchStat = create(ctx.LITERAL_SWITCH());
1030        switchStat.addChild(visit(ctx.parExpression()));
1031        switchStat.addChild(create(ctx.LCURLY()));
1032        switchStat.addChild(visit(ctx.switchBlock()));
1033        switchStat.addChild(create(ctx.RCURLY()));
1034        return switchStat;
1035    }
1036
1037    @Override
1038    public DetailAstImpl visitSwitchRules(JavaLanguageParser.SwitchRulesContext ctx) {
1039        final DetailAstImpl dummyRoot = new DetailAstImpl();
1040        ctx.switchLabeledRule().forEach(switchLabeledRuleContext -> {
1041            final DetailAstImpl switchRule = visit(switchLabeledRuleContext);
1042            final DetailAstImpl switchRuleParent = createImaginary(TokenTypes.SWITCH_RULE);
1043            switchRuleParent.addChild(switchRule);
1044            dummyRoot.addChild(switchRuleParent);
1045        });
1046        return dummyRoot.getFirstChild();
1047    }
1048
1049    @Override
1050    public DetailAstImpl visitSwitchBlocks(JavaLanguageParser.SwitchBlocksContext ctx) {
1051        final DetailAstImpl dummyRoot = new DetailAstImpl();
1052        ctx.groups.forEach(group -> dummyRoot.addChild(visit(group)));
1053
1054        // Add any empty switch labels to end of statement in one 'CASE_GROUP'
1055        if (!ctx.emptyLabels.isEmpty()) {
1056            final DetailAstImpl emptyLabelParent =
1057                    createImaginary(TokenTypes.CASE_GROUP);
1058            ctx.emptyLabels.forEach(label -> emptyLabelParent.addChild(visit(label)));
1059            dummyRoot.addChild(emptyLabelParent);
1060        }
1061        return dummyRoot.getFirstChild();
1062    }
1063
1064    @Override
1065    public DetailAstImpl visitSwitchLabeledExpression(
1066            JavaLanguageParser.SwitchLabeledExpressionContext ctx) {
1067        return flattenedTree(ctx);
1068    }
1069
1070    @Override
1071    public DetailAstImpl visitSwitchLabeledBlock(
1072            JavaLanguageParser.SwitchLabeledBlockContext ctx) {
1073        return flattenedTree(ctx);
1074    }
1075
1076    @Override
1077    public DetailAstImpl visitSwitchLabeledThrow(
1078            JavaLanguageParser.SwitchLabeledThrowContext ctx) {
1079        final DetailAstImpl switchLabel = visit(ctx.switchLabel());
1080        addLastSibling(switchLabel, create(ctx.LAMBDA()));
1081        final DetailAstImpl literalThrow = create(ctx.LITERAL_THROW());
1082        literalThrow.addChild(visit(ctx.expression()));
1083        literalThrow.addChild(create(ctx.SEMI()));
1084        addLastSibling(switchLabel, literalThrow);
1085        return switchLabel;
1086    }
1087
1088    @Override
1089    public DetailAstImpl visitElseStat(JavaLanguageParser.ElseStatContext ctx) {
1090        final DetailAstImpl elseStat = create(ctx.LITERAL_ELSE());
1091        // child[0] is 'LITERAL_ELSE'
1092        processChildren(elseStat, ctx.children.subList(1, ctx.children.size()));
1093        return elseStat;
1094    }
1095
1096    @Override
1097    public DetailAstImpl visitCatchClause(JavaLanguageParser.CatchClauseContext ctx) {
1098        final DetailAstImpl catchClause = create(TokenTypes.LITERAL_CATCH,
1099                (Token) ctx.LITERAL_CATCH().getPayload());
1100        // 'LITERAL_CATCH' is child[0]
1101        processChildren(catchClause, ctx.children.subList(1, ctx.children.size()));
1102        return catchClause;
1103    }
1104
1105    @Override
1106    public DetailAstImpl visitCatchParameter(JavaLanguageParser.CatchParameterContext ctx) {
1107        final DetailAstImpl catchParameterDef = createImaginary(TokenTypes.PARAMETER_DEF);
1108        catchParameterDef.addChild(createModifiers(ctx.mods));
1109        // filter mods
1110        processChildren(catchParameterDef, ctx.children.stream()
1111                .filter(child -> !(child instanceof JavaLanguageParser.VariableModifierContext))
1112                .collect(Collectors.toList()));
1113        return catchParameterDef;
1114    }
1115
1116    @Override
1117    public DetailAstImpl visitCatchType(JavaLanguageParser.CatchTypeContext ctx) {
1118        final DetailAstImpl type = createImaginary(TokenTypes.TYPE);
1119        processChildren(type, ctx.children);
1120        return type;
1121    }
1122
1123    @Override
1124    public DetailAstImpl visitFinallyBlock(JavaLanguageParser.FinallyBlockContext ctx) {
1125        final DetailAstImpl finallyBlock = create(ctx.LITERAL_FINALLY());
1126        // child[0] is 'LITERAL_FINALLY'
1127        processChildren(finallyBlock, ctx.children.subList(1, ctx.children.size()));
1128        return finallyBlock;
1129    }
1130
1131    @Override
1132    public DetailAstImpl visitResourceSpecification(
1133            JavaLanguageParser.ResourceSpecificationContext ctx) {
1134        final DetailAstImpl resourceSpecification =
1135                createImaginary(TokenTypes.RESOURCE_SPECIFICATION);
1136        processChildren(resourceSpecification, ctx.children);
1137        return resourceSpecification;
1138    }
1139
1140    @Override
1141    public DetailAstImpl visitResources(JavaLanguageParser.ResourcesContext ctx) {
1142        final DetailAstImpl firstResource = visit(ctx.resource(0));
1143        final DetailAstImpl resources = createImaginary(TokenTypes.RESOURCES);
1144        resources.addChild(firstResource);
1145        processChildren(resources, ctx.children.subList(1, ctx.children.size()));
1146        return resources;
1147    }
1148
1149    @Override
1150    public DetailAstImpl visitResourceDeclaration(
1151            JavaLanguageParser.ResourceDeclarationContext ctx) {
1152        final DetailAstImpl resource = createImaginary(TokenTypes.RESOURCE);
1153        resource.addChild(visit(ctx.variableDeclaratorId()));
1154
1155        final DetailAstImpl assign = create(ctx.ASSIGN());
1156        resource.addChild(assign);
1157        assign.addChild(visit(ctx.expression()));
1158        return resource;
1159    }
1160
1161    @Override
1162    public DetailAstImpl visitVariableAccess(JavaLanguageParser.VariableAccessContext ctx) {
1163        final DetailAstImpl resource;
1164        if (ctx.accessList.isEmpty()) {
1165            resource = createImaginary(TokenTypes.RESOURCE);
1166            resource.addChild(visit(ctx.id()));
1167        }
1168        else {
1169            final DetailAstPair currentAst = new DetailAstPair();
1170            ctx.accessList.forEach(fieldAccess -> {
1171                DetailAstPair.addAstChild(currentAst, visit(fieldAccess.expr()));
1172                DetailAstPair.makeAstRoot(currentAst, create(fieldAccess.DOT()));
1173            });
1174            resource = createImaginary(TokenTypes.RESOURCE);
1175            resource.addChild(currentAst.root);
1176            if (ctx.LITERAL_THIS() == null) {
1177                resource.getFirstChild().addChild(visit(ctx.id()));
1178            }
1179            else {
1180                resource.getFirstChild().addChild(create(ctx.LITERAL_THIS()));
1181            }
1182        }
1183        return resource;
1184    }
1185
1186    @Override
1187    public DetailAstImpl visitSwitchBlockStatementGroup(
1188            JavaLanguageParser.SwitchBlockStatementGroupContext ctx) {
1189        final DetailAstImpl caseGroup = createImaginary(TokenTypes.CASE_GROUP);
1190        processChildren(caseGroup, ctx.switchLabel());
1191        final DetailAstImpl sList = createImaginary(TokenTypes.SLIST);
1192        processChildren(sList, ctx.slists);
1193        caseGroup.addChild(sList);
1194        return caseGroup;
1195    }
1196
1197    @Override
1198    public DetailAstImpl visitCaseLabel(JavaLanguageParser.CaseLabelContext ctx) {
1199        final DetailAstImpl caseLabel = create(ctx.LITERAL_CASE());
1200        // child [0] is 'LITERAL_CASE'
1201        processChildren(caseLabel, ctx.children.subList(1, ctx.children.size()));
1202        return caseLabel;
1203    }
1204
1205    @Override
1206    public DetailAstImpl visitDefaultLabel(JavaLanguageParser.DefaultLabelContext ctx) {
1207        final DetailAstImpl defaultLabel = create(ctx.LITERAL_DEFAULT());
1208        if (ctx.COLON() != null) {
1209            defaultLabel.addChild(create(ctx.COLON()));
1210        }
1211        return defaultLabel;
1212    }
1213
1214    @Override
1215    public DetailAstImpl visitCaseConstants(JavaLanguageParser.CaseConstantsContext ctx) {
1216        return flattenedTree(ctx);
1217    }
1218
1219    @Override
1220    public DetailAstImpl visitEnhancedFor(JavaLanguageParser.EnhancedForContext ctx) {
1221        final DetailAstImpl leftParen = create(ctx.LPAREN());
1222        final DetailAstImpl enhancedForControl =
1223                 visit(ctx.enhancedForControl());
1224        final DetailAstImpl forEachClause = createImaginary(TokenTypes.FOR_EACH_CLAUSE);
1225        forEachClause.addChild(enhancedForControl);
1226        addLastSibling(leftParen, forEachClause);
1227        addLastSibling(leftParen, create(ctx.RPAREN()));
1228        return leftParen;
1229    }
1230
1231    @Override
1232    public DetailAstImpl visitForFor(JavaLanguageParser.ForForContext ctx) {
1233        final DetailAstImpl dummyRoot = new DetailAstImpl();
1234        dummyRoot.addChild(create(ctx.LPAREN()));
1235
1236        if (ctx.forInit() == null) {
1237            final DetailAstImpl imaginaryForInitParent =
1238                    createImaginary(TokenTypes.FOR_INIT);
1239            dummyRoot.addChild(imaginaryForInitParent);
1240        }
1241        else {
1242            dummyRoot.addChild(visit(ctx.forInit()));
1243        }
1244
1245        dummyRoot.addChild(create(ctx.SEMI(0)));
1246
1247        final DetailAstImpl forCondParent = createImaginary(TokenTypes.FOR_CONDITION);
1248        forCondParent.addChild(visit(ctx.forCond));
1249        dummyRoot.addChild(forCondParent);
1250        dummyRoot.addChild(create(ctx.SEMI(1)));
1251
1252        final DetailAstImpl forItParent = createImaginary(TokenTypes.FOR_ITERATOR);
1253        forItParent.addChild(visit(ctx.forUpdate));
1254        dummyRoot.addChild(forItParent);
1255
1256        dummyRoot.addChild(create(ctx.RPAREN()));
1257
1258        return dummyRoot.getFirstChild();
1259    }
1260
1261    @Override
1262    public DetailAstImpl visitForInit(JavaLanguageParser.ForInitContext ctx) {
1263        final DetailAstImpl forInit = createImaginary(TokenTypes.FOR_INIT);
1264        processChildren(forInit, ctx.children);
1265        return forInit;
1266    }
1267
1268    @Override
1269    public DetailAstImpl visitEnhancedForControl(
1270            JavaLanguageParser.EnhancedForControlContext ctx) {
1271        final DetailAstImpl variableDeclaratorId =
1272                 visit(ctx.variableDeclaratorId());
1273        final DetailAstImpl variableDef = createImaginary(TokenTypes.VARIABLE_DEF);
1274        variableDef.addChild(variableDeclaratorId);
1275
1276        addLastSibling(variableDef, create(ctx.COLON()));
1277        addLastSibling(variableDef, visit(ctx.expression()));
1278        return variableDef;
1279    }
1280
1281    @Override
1282    public DetailAstImpl visitParExpression(JavaLanguageParser.ParExpressionContext ctx) {
1283        return flattenedTree(ctx);
1284    }
1285
1286    @Override
1287    public DetailAstImpl visitExpressionList(JavaLanguageParser.ExpressionListContext ctx) {
1288        final DetailAstImpl elist = createImaginary(TokenTypes.ELIST);
1289        processChildren(elist, ctx.children);
1290        return elist;
1291    }
1292
1293    @Override
1294    public DetailAstImpl visitExpression(JavaLanguageParser.ExpressionContext ctx) {
1295        final DetailAstImpl expression = visit(ctx.expr());
1296        DetailAstImpl exprRoot = createImaginary(TokenTypes.EXPR);
1297        exprRoot.addChild(expression);
1298
1299        final int[] expressionsWithNoExprRoot = {
1300            TokenTypes.CTOR_CALL,
1301            TokenTypes.SUPER_CTOR_CALL,
1302            TokenTypes.LAMBDA,
1303        };
1304
1305        if (TokenUtil.isOfType(expression, expressionsWithNoExprRoot)) {
1306            exprRoot = exprRoot.getFirstChild();
1307        }
1308
1309        return exprRoot;
1310    }
1311
1312    @Override
1313    public DetailAstImpl visitRefOp(JavaLanguageParser.RefOpContext ctx) {
1314        final DetailAstImpl bop = create(ctx.bop);
1315        final DetailAstImpl leftChild = visit(ctx.expr());
1316        final DetailAstImpl rightChild = create(TokenTypes.IDENT, ctx.stop);
1317        bop.addChild(leftChild);
1318        bop.addChild(rightChild);
1319        return bop;
1320    }
1321
1322    @Override
1323    public DetailAstImpl visitSuperExp(JavaLanguageParser.SuperExpContext ctx) {
1324        final DetailAstImpl bop = create(ctx.bop);
1325        bop.addChild(visit(ctx.expr()));
1326        bop.addChild(create(ctx.LITERAL_SUPER()));
1327        DetailAstImpl superSuffixParent = visit(ctx.superSuffix());
1328
1329        if (superSuffixParent == null) {
1330            superSuffixParent = bop;
1331        }
1332        else {
1333            DetailAstImpl firstChild = superSuffixParent.getFirstChild();
1334            while (firstChild.getFirstChild() != null) {
1335                firstChild = firstChild.getFirstChild();
1336            }
1337            firstChild.addPreviousSibling(bop);
1338        }
1339
1340        return superSuffixParent;
1341    }
1342
1343    @Override
1344    public DetailAstImpl visitInstanceOfExp(JavaLanguageParser.InstanceOfExpContext ctx) {
1345        final DetailAstImpl literalInstanceOf = create(ctx.LITERAL_INSTANCEOF());
1346        literalInstanceOf.addChild(visit(ctx.expr()));
1347        literalInstanceOf.addChild(visit(ctx.children.get(2)));
1348        return literalInstanceOf;
1349    }
1350
1351    @Override
1352    public DetailAstImpl visitBitShift(JavaLanguageParser.BitShiftContext ctx) {
1353        final DetailAstImpl shiftOperation;
1354
1355        // We determine the type of shift operation in the parser, instead of the
1356        // lexer as in older grammars. This makes it easier to parse type parameters
1357        // and less than/ greater than operators in general.
1358        if (ctx.LT().size() == LEFT_SHIFT.length()) {
1359            shiftOperation = create(TokenTypes.SL, (Token) ctx.LT(0).getPayload());
1360            shiftOperation.setText(LEFT_SHIFT);
1361        }
1362        else if (ctx.GT().size() == UNSIGNED_RIGHT_SHIFT.length()) {
1363            shiftOperation = create(TokenTypes.BSR, (Token) ctx.GT(0).getPayload());
1364            shiftOperation.setText(UNSIGNED_RIGHT_SHIFT);
1365        }
1366        else {
1367            shiftOperation = create(TokenTypes.SR, (Token) ctx.GT(0).getPayload());
1368            shiftOperation.setText(RIGHT_SHIFT);
1369        }
1370
1371        shiftOperation.addChild(visit(ctx.expr(0)));
1372        shiftOperation.addChild(visit(ctx.expr(1)));
1373        return shiftOperation;
1374    }
1375
1376    @Override
1377    public DetailAstImpl visitNewExp(JavaLanguageParser.NewExpContext ctx) {
1378        final DetailAstImpl newExp = create(ctx.LITERAL_NEW());
1379        // child [0] is LITERAL_NEW
1380        processChildren(newExp, ctx.children.subList(1, ctx.children.size()));
1381        return newExp;
1382    }
1383
1384    @Override
1385    public DetailAstImpl visitPrefix(JavaLanguageParser.PrefixContext ctx) {
1386        final int tokenType;
1387        switch (ctx.prefix.getType()) {
1388            case JavaLanguageLexer.PLUS:
1389                tokenType = TokenTypes.UNARY_PLUS;
1390                break;
1391            case JavaLanguageLexer.MINUS:
1392                tokenType = TokenTypes.UNARY_MINUS;
1393                break;
1394            default:
1395                tokenType = ctx.prefix.getType();
1396        }
1397        final DetailAstImpl prefix = create(tokenType, ctx.prefix);
1398        prefix.addChild(visit(ctx.expr()));
1399        return prefix;
1400    }
1401
1402    @Override
1403    public DetailAstImpl visitCastExp(JavaLanguageParser.CastExpContext ctx) {
1404        final DetailAstImpl cast = create(TokenTypes.TYPECAST, (Token) ctx.LPAREN().getPayload());
1405        // child [0] is LPAREN
1406        processChildren(cast, ctx.children.subList(1, ctx.children.size()));
1407        return cast;
1408    }
1409
1410    @Override
1411    public DetailAstImpl visitIndexOp(JavaLanguageParser.IndexOpContext ctx) {
1412        // LBRACK -> INDEX_OP is root of this AST
1413        final DetailAstImpl indexOp = create(TokenTypes.INDEX_OP,
1414                (Token) ctx.LBRACK().getPayload());
1415
1416        // add expression(IDENT) on LHS
1417        indexOp.addChild(visit(ctx.expr(0)));
1418
1419        // create imaginary node for expression on RHS
1420        final DetailAstImpl expr = visit(ctx.expr(1));
1421        final DetailAstImpl imaginaryExpr = createImaginary(TokenTypes.EXPR);
1422        imaginaryExpr.addChild(expr);
1423        indexOp.addChild(imaginaryExpr);
1424
1425        // complete AST by adding RBRACK
1426        indexOp.addChild(create(ctx.RBRACK()));
1427        return indexOp;
1428    }
1429
1430    @Override
1431    public DetailAstImpl visitInvOp(JavaLanguageParser.InvOpContext ctx) {
1432        final DetailAstPair currentAst = new DetailAstPair();
1433
1434        final DetailAstImpl returnAst = visit(ctx.expr());
1435        DetailAstPair.addAstChild(currentAst, returnAst);
1436        DetailAstPair.makeAstRoot(currentAst, create(ctx.bop));
1437
1438        DetailAstPair.addAstChild(currentAst,
1439                 visit(ctx.nonWildcardTypeArguments()));
1440        DetailAstPair.addAstChild(currentAst, visit(ctx.id()));
1441        final DetailAstImpl lparen = create(TokenTypes.METHOD_CALL,
1442                (Token) ctx.LPAREN().getPayload());
1443        DetailAstPair.makeAstRoot(currentAst, lparen);
1444
1445        // We always add an 'ELIST' node
1446        final DetailAstImpl expressionList = Optional.ofNullable(visit(ctx.expressionList()))
1447                .orElse(createImaginary(TokenTypes.ELIST));
1448
1449        DetailAstPair.addAstChild(currentAst, expressionList);
1450        DetailAstPair.addAstChild(currentAst, create(ctx.RPAREN()));
1451
1452        return currentAst.root;
1453    }
1454
1455    @Override
1456    public DetailAstImpl visitInitExp(JavaLanguageParser.InitExpContext ctx) {
1457        final DetailAstImpl dot = create(ctx.bop);
1458        dot.addChild(visit(ctx.expr()));
1459        final DetailAstImpl literalNew = create(ctx.LITERAL_NEW());
1460        literalNew.addChild(visit(ctx.nonWildcardTypeArguments()));
1461        literalNew.addChild(visit(ctx.innerCreator()));
1462        dot.addChild(literalNew);
1463        return dot;
1464    }
1465
1466    @Override
1467    public DetailAstImpl visitSimpleMethodCall(JavaLanguageParser.SimpleMethodCallContext ctx) {
1468        final DetailAstImpl methodCall = create(TokenTypes.METHOD_CALL,
1469                (Token) ctx.LPAREN().getPayload());
1470        methodCall.addChild(visit(ctx.id()));
1471        // We always add an 'ELIST' node
1472        final DetailAstImpl expressionList = Optional.ofNullable(visit(ctx.expressionList()))
1473                .orElse(createImaginary(TokenTypes.ELIST));
1474
1475        methodCall.addChild(expressionList);
1476        methodCall.addChild(create((Token) ctx.RPAREN().getPayload()));
1477        return methodCall;
1478    }
1479
1480    @Override
1481    public DetailAstImpl visitLambdaExp(JavaLanguageParser.LambdaExpContext ctx) {
1482        return flattenedTree(ctx);
1483    }
1484
1485    @Override
1486    public DetailAstImpl visitThisExp(JavaLanguageParser.ThisExpContext ctx) {
1487        final DetailAstImpl bop = create(ctx.bop);
1488        bop.addChild(visit(ctx.expr()));
1489        bop.addChild(create(ctx.LITERAL_THIS()));
1490        return bop;
1491    }
1492
1493    @Override
1494    public DetailAstImpl visitPrimaryExp(JavaLanguageParser.PrimaryExpContext ctx) {
1495        return flattenedTree(ctx);
1496    }
1497
1498    @Override
1499    public DetailAstImpl visitPostfix(JavaLanguageParser.PostfixContext ctx) {
1500        final DetailAstImpl postfix;
1501        if (ctx.postfix.getType() == JavaLanguageLexer.INC) {
1502            postfix = create(TokenTypes.POST_INC, ctx.postfix);
1503        }
1504        else {
1505            postfix = create(TokenTypes.POST_DEC, ctx.postfix);
1506        }
1507        postfix.addChild(visit(ctx.expr()));
1508        return postfix;
1509    }
1510
1511    @Override
1512    public DetailAstImpl visitMethodRef(JavaLanguageParser.MethodRefContext ctx) {
1513        final DetailAstImpl doubleColon = create(TokenTypes.METHOD_REF,
1514                (Token) ctx.DOUBLE_COLON().getPayload());
1515        final List<ParseTree> children = ctx.children.stream()
1516                .filter(child -> !child.equals(ctx.DOUBLE_COLON()))
1517                .collect(Collectors.toList());
1518        processChildren(doubleColon, children);
1519        return doubleColon;
1520    }
1521
1522    @Override
1523    public DetailAstImpl visitTernaryOp(JavaLanguageParser.TernaryOpContext ctx) {
1524        final DetailAstImpl root = create(ctx.QUESTION());
1525        processChildren(root, ctx.children.stream()
1526                .filter(child -> !child.equals(ctx.QUESTION()))
1527                .collect(Collectors.toList()));
1528        return root;
1529    }
1530
1531    @Override
1532    public DetailAstImpl visitBinOp(JavaLanguageParser.BinOpContext ctx) {
1533        final DetailAstImpl bop = create(ctx.bop);
1534
1535        // To improve performance, we iterate through binary operations
1536        // since they are frequently deeply nested.
1537        final List<JavaLanguageParser.BinOpContext> binOpList = new ArrayList<>();
1538        ParseTree firstExpression = ctx.expr(0);
1539        while (firstExpression instanceof JavaLanguageParser.BinOpContext) {
1540            // Get all nested binOps
1541            binOpList.add((JavaLanguageParser.BinOpContext) firstExpression);
1542            firstExpression = ((JavaLanguageParser.BinOpContext) firstExpression).expr(0);
1543        }
1544
1545        if (binOpList.isEmpty()) {
1546            final DetailAstImpl leftChild = visit(ctx.children.get(0));
1547            bop.addChild(leftChild);
1548        }
1549        else {
1550            // Map all descendants to individual AST's since we can parallelize this
1551            // operation
1552            final Queue<DetailAstImpl> descendantList = binOpList.parallelStream()
1553                    .map(this::getInnerBopAst)
1554                    .collect(Collectors.toCollection(ConcurrentLinkedQueue::new));
1555
1556            bop.addChild(descendantList.poll());
1557            DetailAstImpl pointer = bop.getFirstChild();
1558            // Build tree
1559            for (DetailAstImpl descendant : descendantList) {
1560                pointer.getFirstChild().addPreviousSibling(descendant);
1561                pointer = descendant;
1562            }
1563        }
1564
1565        bop.addChild(visit(ctx.children.get(2)));
1566        return bop;
1567    }
1568
1569    /**
1570     * Builds the binary operation (binOp) AST.
1571     *
1572     * @param descendant the BinOpContext to build AST from
1573     * @return binOp AST
1574     */
1575    private DetailAstImpl getInnerBopAst(JavaLanguageParser.BinOpContext descendant) {
1576        final DetailAstImpl innerBop = create(descendant.bop);
1577        if (!(descendant.expr(0) instanceof JavaLanguageParser.BinOpContext)) {
1578            innerBop.addChild(visit(descendant.expr(0)));
1579        }
1580        innerBop.addChild(visit(descendant.expr(1)));
1581        return innerBop;
1582    }
1583
1584    @Override
1585    public DetailAstImpl visitMethodCall(JavaLanguageParser.MethodCallContext ctx) {
1586        final DetailAstImpl methodCall = create(TokenTypes.METHOD_CALL,
1587                (Token) ctx.LPAREN().getPayload());
1588        // We always add an 'ELIST' node
1589        final DetailAstImpl expressionList = Optional.ofNullable(visit(ctx.expressionList()))
1590                .orElse(createImaginary(TokenTypes.ELIST));
1591
1592        final DetailAstImpl dot = create(ctx.DOT());
1593        dot.addChild(visit(ctx.expr()));
1594        dot.addChild(visit(ctx.id()));
1595        methodCall.addChild(dot);
1596        methodCall.addChild(expressionList);
1597        methodCall.addChild(create((Token) ctx.RPAREN().getPayload()));
1598        return methodCall;
1599    }
1600
1601    @Override
1602    public DetailAstImpl visitTypeCastParameters(
1603            JavaLanguageParser.TypeCastParametersContext ctx) {
1604        final DetailAstImpl typeType = visit(ctx.typeType(0));
1605        for (int i = 0; i < ctx.BAND().size(); i++) {
1606            addLastSibling(typeType, create(TokenTypes.TYPE_EXTENSION_AND,
1607                                (Token) ctx.BAND(i).getPayload()));
1608            addLastSibling(typeType, visit(ctx.typeType(i + 1)));
1609        }
1610        return typeType;
1611    }
1612
1613    @Override
1614    public DetailAstImpl visitLambdaExpression(JavaLanguageParser.LambdaExpressionContext ctx) {
1615        final DetailAstImpl lambda = create(ctx.LAMBDA());
1616        lambda.addChild(visit(ctx.lambdaParameters()));
1617        lambda.addChild(visit(ctx.lambdaBody()));
1618        return lambda;
1619    }
1620
1621    @Override
1622    public DetailAstImpl visitSingleLambdaParam(JavaLanguageParser.SingleLambdaParamContext ctx) {
1623        return flattenedTree(ctx);
1624    }
1625
1626    @Override
1627    public DetailAstImpl visitFormalLambdaParam(JavaLanguageParser.FormalLambdaParamContext ctx) {
1628        final DetailAstImpl lparen = create(ctx.LPAREN());
1629
1630        // We add an 'PARAMETERS' node here whether it exists or not
1631        final DetailAstImpl parameters = Optional.ofNullable(visit(ctx.formalParameterList()))
1632                .orElse(createImaginary(TokenTypes.PARAMETERS));
1633        addLastSibling(lparen, parameters);
1634        addLastSibling(lparen, create(ctx.RPAREN()));
1635        return lparen;
1636    }
1637
1638    @Override
1639    public DetailAstImpl visitMultiLambdaParam(JavaLanguageParser.MultiLambdaParamContext ctx) {
1640        final DetailAstImpl lparen = create(ctx.LPAREN());
1641        addLastSibling(lparen, visit(ctx.multiLambdaParams()));
1642        addLastSibling(lparen, create(ctx.RPAREN()));
1643        return lparen;
1644    }
1645
1646    @Override
1647    public DetailAstImpl visitMultiLambdaParams(JavaLanguageParser.MultiLambdaParamsContext ctx) {
1648        final DetailAstImpl parameters = createImaginary(TokenTypes.PARAMETERS);
1649        parameters.addChild(createLambdaParameter(ctx.id(0)));
1650
1651        for (int i = 0; i < ctx.COMMA().size(); i++) {
1652            parameters.addChild(create(ctx.COMMA(i)));
1653            parameters.addChild(createLambdaParameter(ctx.id(i + 1)));
1654        }
1655        return parameters;
1656    }
1657
1658    /**
1659     * Creates a 'PARAMETER_DEF' node for a lambda expression, with
1660     * imaginary modifier and type nodes.
1661     *
1662     * @param ctx the IdContext to create imaginary nodes for
1663     * @return DetailAstImpl of lambda parameter
1664     */
1665    private DetailAstImpl createLambdaParameter(JavaLanguageParser.IdContext ctx) {
1666        final DetailAstImpl ident = visitId(ctx);
1667        final DetailAstImpl parameter = createImaginary(TokenTypes.PARAMETER_DEF);
1668        final DetailAstImpl modifiers = createImaginary(TokenTypes.MODIFIERS);
1669        final DetailAstImpl type = createImaginary(TokenTypes.TYPE);
1670        parameter.addChild(modifiers);
1671        parameter.addChild(type);
1672        parameter.addChild(ident);
1673        return parameter;
1674    }
1675
1676    @Override
1677    public DetailAstImpl visitParenPrimary(JavaLanguageParser.ParenPrimaryContext ctx) {
1678        return flattenedTree(ctx);
1679    }
1680
1681    @Override
1682    public DetailAstImpl visitTokenPrimary(JavaLanguageParser.TokenPrimaryContext ctx) {
1683        return flattenedTree(ctx);
1684    }
1685
1686    @Override
1687    public DetailAstImpl visitClassRefPrimary(JavaLanguageParser.ClassRefPrimaryContext ctx) {
1688        final DetailAstImpl dot = create(ctx.DOT());
1689        final DetailAstImpl primaryTypeNoArray = visit(ctx.type);
1690        dot.addChild(primaryTypeNoArray);
1691        if (TokenUtil.isOfType(primaryTypeNoArray, TokenTypes.DOT)) {
1692            // We append '[]' to the qualified name 'TYPE' `ast
1693            ctx.arrayDeclarator()
1694                    .forEach(child -> primaryTypeNoArray.addChild(visit(child)));
1695        }
1696        else {
1697            ctx.arrayDeclarator()
1698                    .forEach(child -> addLastSibling(primaryTypeNoArray, visit(child)));
1699        }
1700        dot.addChild(create(ctx.LITERAL_CLASS()));
1701        return dot;
1702    }
1703
1704    @Override
1705    public DetailAstImpl visitPrimitivePrimary(JavaLanguageParser.PrimitivePrimaryContext ctx) {
1706        final DetailAstImpl dot = create(ctx.DOT());
1707        final DetailAstImpl primaryTypeNoArray = visit(ctx.type);
1708        dot.addChild(primaryTypeNoArray);
1709        ctx.arrayDeclarator().forEach(child -> dot.addChild(visit(child)));
1710        dot.addChild(create(ctx.LITERAL_CLASS()));
1711        return dot;
1712    }
1713
1714    @Override
1715    public DetailAstImpl visitCreator(JavaLanguageParser.CreatorContext ctx) {
1716        return flattenedTree(ctx);
1717    }
1718
1719    @Override
1720    public DetailAstImpl visitCreatedNameObject(JavaLanguageParser.CreatedNameObjectContext ctx) {
1721        final DetailAstPair currentAST = new DetailAstPair();
1722        DetailAstPair.addAstChild(currentAST, visit(ctx.annotations()));
1723        DetailAstPair.addAstChild(currentAST, visit(ctx.id()));
1724        DetailAstPair.addAstChild(currentAST, visit(ctx.typeArgumentsOrDiamond()));
1725
1726        // This is how we build the type arguments/ qualified name tree
1727        for (int i = 0; i < ctx.extended.size(); i++) {
1728            final ParserRuleContext extendedContext = ctx.extended.get(i);
1729            final DetailAstImpl dot = create(extendedContext.start);
1730            DetailAstPair.makeAstRoot(currentAST, dot);
1731            final List<ParseTree> childList = extendedContext
1732                    .children.subList(1, extendedContext.children.size());
1733            processChildren(dot, childList);
1734        }
1735
1736        return currentAST.root;
1737    }
1738
1739    @Override
1740    public DetailAstImpl visitCreatedNamePrimitive(
1741            JavaLanguageParser.CreatedNamePrimitiveContext ctx) {
1742        return flattenedTree(ctx);
1743    }
1744
1745    @Override
1746    public DetailAstImpl visitInnerCreator(JavaLanguageParser.InnerCreatorContext ctx) {
1747        return flattenedTree(ctx);
1748    }
1749
1750    @Override
1751    public DetailAstImpl visitArrayCreatorRest(JavaLanguageParser.ArrayCreatorRestContext ctx) {
1752        final DetailAstImpl arrayDeclarator = create(TokenTypes.ARRAY_DECLARATOR,
1753                (Token) ctx.LBRACK().getPayload());
1754        // child[0] is LBRACK
1755        for (int i = 1; i < ctx.children.size(); i++) {
1756            if (ctx.children.get(i) == ctx.RBRACK()) {
1757                arrayDeclarator.addChild(create(ctx.RBRACK()));
1758            }
1759            else if (ctx.children.get(i) == ctx.expression()) {
1760                // Handle '[8]', etc.
1761                arrayDeclarator.addChild(visit(ctx.expression()));
1762            }
1763            else {
1764                addLastSibling(arrayDeclarator, visit(ctx.children.get(i)));
1765            }
1766        }
1767        return arrayDeclarator;
1768    }
1769
1770    @Override
1771    public DetailAstImpl visitBracketsWithExp(JavaLanguageParser.BracketsWithExpContext ctx) {
1772        final DetailAstImpl dummyRoot = new DetailAstImpl();
1773        dummyRoot.addChild(visit(ctx.annotations()));
1774        final DetailAstImpl arrayDeclarator =
1775                create(TokenTypes.ARRAY_DECLARATOR, (Token) ctx.LBRACK().getPayload());
1776        arrayDeclarator.addChild(visit(ctx.expression()));
1777        arrayDeclarator.addChild(create(ctx.stop));
1778        dummyRoot.addChild(arrayDeclarator);
1779        return dummyRoot.getFirstChild();
1780    }
1781
1782    @Override
1783    public DetailAstImpl visitClassCreatorRest(JavaLanguageParser.ClassCreatorRestContext ctx) {
1784        return flattenedTree(ctx);
1785    }
1786
1787    @Override
1788    public DetailAstImpl visitDiamond(JavaLanguageParser.DiamondContext ctx) {
1789        final DetailAstImpl typeArguments =
1790                createImaginary(TokenTypes.TYPE_ARGUMENTS);
1791        typeArguments.addChild(create(TokenTypes.GENERIC_START,
1792                (Token) ctx.LT().getPayload()));
1793        typeArguments.addChild(create(TokenTypes.GENERIC_END,
1794                (Token) ctx.GT().getPayload()));
1795        return typeArguments;
1796    }
1797
1798    @Override
1799    public DetailAstImpl visitTypeArgs(JavaLanguageParser.TypeArgsContext ctx) {
1800        return flattenedTree(ctx);
1801    }
1802
1803    @Override
1804    public DetailAstImpl visitNonWildcardDiamond(
1805            JavaLanguageParser.NonWildcardDiamondContext ctx) {
1806        final DetailAstImpl typeArguments =
1807                createImaginary(TokenTypes.TYPE_ARGUMENTS);
1808        typeArguments.addChild(create(TokenTypes.GENERIC_START,
1809                (Token) ctx.LT().getPayload()));
1810        typeArguments.addChild(create(TokenTypes.GENERIC_END,
1811                (Token) ctx.GT().getPayload()));
1812        return typeArguments;
1813    }
1814
1815    @Override
1816    public DetailAstImpl visitNonWildcardTypeArguments(
1817            JavaLanguageParser.NonWildcardTypeArgumentsContext ctx) {
1818        final DetailAstImpl typeArguments = createImaginary(TokenTypes.TYPE_ARGUMENTS);
1819        typeArguments.addChild(create(TokenTypes.GENERIC_START, (Token) ctx.LT().getPayload()));
1820        typeArguments.addChild(visit(ctx.typeArgumentsTypeList()));
1821        typeArguments.addChild(create(TokenTypes.GENERIC_END, (Token) ctx.GT().getPayload()));
1822        return typeArguments;
1823    }
1824
1825    @Override
1826    public DetailAstImpl visitTypeArgumentsTypeList(
1827            JavaLanguageParser.TypeArgumentsTypeListContext ctx) {
1828        final DetailAstImpl firstIdent = visit(ctx.typeType(0));
1829        final DetailAstImpl firstTypeArgument = createImaginary(TokenTypes.TYPE_ARGUMENT);
1830        firstTypeArgument.addChild(firstIdent);
1831
1832        for (int i = 0; i < ctx.COMMA().size(); i++) {
1833            addLastSibling(firstTypeArgument, create(ctx.COMMA(i)));
1834            final DetailAstImpl ident = visit(ctx.typeType(i + 1));
1835            final DetailAstImpl typeArgument = createImaginary(TokenTypes.TYPE_ARGUMENT);
1836            typeArgument.addChild(ident);
1837            addLastSibling(firstTypeArgument, typeArgument);
1838        }
1839        return firstTypeArgument;
1840    }
1841
1842    @Override
1843    public DetailAstImpl visitTypeList(JavaLanguageParser.TypeListContext ctx) {
1844        return flattenedTree(ctx);
1845    }
1846
1847    @Override
1848    public DetailAstImpl visitTypeType(JavaLanguageParser.TypeTypeContext ctx) {
1849        final DetailAstImpl type = createImaginary(TokenTypes.TYPE);
1850        processChildren(type, ctx.children);
1851
1852        final DetailAstImpl returnTree;
1853        if (ctx.createImaginaryNode) {
1854            returnTree = type;
1855        }
1856        else {
1857            returnTree = type.getFirstChild();
1858        }
1859        return returnTree;
1860    }
1861
1862    @Override
1863    public DetailAstImpl visitArrayDeclarator(JavaLanguageParser.ArrayDeclaratorContext ctx) {
1864        final DetailAstImpl arrayDeclarator = create(TokenTypes.ARRAY_DECLARATOR,
1865                (Token) ctx.LBRACK().getPayload());
1866        arrayDeclarator.addChild(create(ctx.RBRACK()));
1867
1868        final DetailAstImpl returnTree;
1869        final DetailAstImpl annotations = visit(ctx.anno);
1870        if (annotations == null) {
1871            returnTree = arrayDeclarator;
1872        }
1873        else {
1874            returnTree = annotations;
1875            addLastSibling(returnTree, arrayDeclarator);
1876        }
1877        return returnTree;
1878    }
1879
1880    @Override
1881    public DetailAstImpl visitPrimitiveType(JavaLanguageParser.PrimitiveTypeContext ctx) {
1882        return create(ctx.start);
1883    }
1884
1885    @Override
1886    public DetailAstImpl visitTypeArguments(JavaLanguageParser.TypeArgumentsContext ctx) {
1887        final DetailAstImpl typeArguments = createImaginary(TokenTypes.TYPE_ARGUMENTS);
1888        typeArguments.addChild(create(TokenTypes.GENERIC_START, (Token) ctx.LT().getPayload()));
1889        // Exclude '<' and '>'
1890        processChildren(typeArguments, ctx.children.subList(1, ctx.children.size() - 1));
1891        typeArguments.addChild(create(TokenTypes.GENERIC_END, (Token) ctx.GT().getPayload()));
1892        return typeArguments;
1893    }
1894
1895    @Override
1896    public DetailAstImpl visitSuperSuffixDot(JavaLanguageParser.SuperSuffixDotContext ctx) {
1897        final DetailAstImpl root;
1898        if (ctx.LPAREN() == null) {
1899            root = create(ctx.DOT());
1900            root.addChild(visit(ctx.id()));
1901        }
1902        else {
1903            root = create(TokenTypes.METHOD_CALL, (Token) ctx.LPAREN().getPayload());
1904
1905            final DetailAstImpl dot = create(ctx.DOT());
1906            dot.addChild(visit(ctx.id()));
1907            root.addChild(dot);
1908
1909            final DetailAstImpl expressionList = Optional.ofNullable(visit(ctx.expressionList()))
1910                    .orElse(createImaginary(TokenTypes.ELIST));
1911            root.addChild(expressionList);
1912
1913            root.addChild(create(ctx.RPAREN()));
1914        }
1915
1916        return root;
1917    }
1918
1919    @Override
1920    public DetailAstImpl visitArguments(JavaLanguageParser.ArgumentsContext ctx) {
1921        final DetailAstImpl lparen = create(ctx.LPAREN());
1922
1923        // We always add an 'ELIST' node
1924        final DetailAstImpl expressionList = Optional.ofNullable(visit(ctx.expressionList()))
1925                .orElse(createImaginary(TokenTypes.ELIST));
1926        addLastSibling(lparen, expressionList);
1927        addLastSibling(lparen, create(ctx.RPAREN()));
1928        return lparen;
1929    }
1930
1931    @Override
1932    public DetailAstImpl visitPatternVariableDefinition(
1933            JavaLanguageParser.PatternVariableDefinitionContext ctx) {
1934        final DetailAstImpl type = visit(ctx.type);
1935        final DetailAstImpl patternVariableDef = createImaginary(TokenTypes.PATTERN_VARIABLE_DEF);
1936        patternVariableDef.addChild(createModifiers(ctx.mods));
1937        patternVariableDef.addChild(type);
1938        patternVariableDef.addChild(visit(ctx.id()));
1939        return patternVariableDef;
1940    }
1941
1942    @Override
1943    public DetailAstImpl visitPermittedSubclassesAndInterfaces(
1944            JavaLanguageParser.PermittedSubclassesAndInterfacesContext ctx) {
1945        final DetailAstImpl literalPermits =
1946                create(TokenTypes.PERMITS_CLAUSE, (Token) ctx.LITERAL_PERMITS().getPayload());
1947        // 'LITERAL_PERMITS' is child[0]
1948        processChildren(literalPermits, ctx.children.subList(1, ctx.children.size()));
1949        return literalPermits;
1950    }
1951
1952    @Override
1953    public DetailAstImpl visitId(JavaLanguageParser.IdContext ctx) {
1954        return create(TokenTypes.IDENT, ctx.start);
1955    }
1956
1957    /**
1958     * Builds the AST for a particular node, then returns a "flattened" tree
1959     * of siblings. This method should be used in rule contexts such as
1960     * {@code variableDeclarators}, where we have both terminals and non-terminals.
1961     *
1962     * @param ctx the ParserRuleContext to base tree on
1963     * @return flattened DetailAstImpl
1964     */
1965    private DetailAstImpl flattenedTree(ParserRuleContext ctx) {
1966        final DetailAstImpl dummyNode = new DetailAstImpl();
1967        processChildren(dummyNode, ctx.children);
1968        return dummyNode.getFirstChild();
1969    }
1970
1971    /**
1972     * Adds all the children from the given ParseTree or JavaParserContext
1973     * list to the parent DetailAstImpl.
1974     *
1975     * @param parent the DetailAstImpl to add children to
1976     * @param children the list of children to add
1977     */
1978    private void processChildren(DetailAstImpl parent, List<? extends ParseTree> children) {
1979        children.forEach(child -> {
1980            if (child instanceof TerminalNode) {
1981                // Child is a token, create a new DetailAstImpl and add it to parent
1982                parent.addChild(create((TerminalNode) child));
1983            }
1984            else {
1985                // Child is another rule context; visit it, create token, and add to parent
1986                parent.addChild(visit(child));
1987            }
1988        });
1989    }
1990
1991    /**
1992     * Create a DetailAstImpl from a given token and token type. This method
1993     * should be used for imaginary nodes only, i.e. 'OBJBLOCK -&gt; OBJBLOCK',
1994     * where the text on the RHS matches the text on the LHS.
1995     *
1996     * @param tokenType  the token type of this DetailAstImpl
1997     * @return new DetailAstImpl of given type
1998     */
1999    private static DetailAstImpl createImaginary(int tokenType) {
2000        final DetailAstImpl detailAst = new DetailAstImpl();
2001        detailAst.setType(tokenType);
2002        detailAst.setText(TokenUtil.getTokenName(tokenType));
2003        return detailAst;
2004    }
2005
2006    /**
2007     * Create a DetailAstImpl from a given token and token type. This method
2008     * should be used for literal nodes only, i.e. 'PACKAGE_DEF -&gt; package'.
2009     *
2010     * @param tokenType the token type of this DetailAstImpl
2011     * @param startToken the first token that appears in this DetailAstImpl.
2012     * @return new DetailAstImpl of given type
2013     */
2014    private DetailAstImpl create(int tokenType, Token startToken) {
2015        final DetailAstImpl ast = create(startToken);
2016        ast.setType(tokenType);
2017        return ast;
2018    }
2019
2020    /**
2021     * Create a DetailAstImpl from a given token. This method should be
2022     * used for terminal nodes, i.e. {@code LCURLY}, when we are building
2023     * an AST for a specific token, regardless of position.
2024     *
2025     * @param token the token to build the DetailAstImpl from
2026     * @return new DetailAstImpl of given type
2027     */
2028    private DetailAstImpl create(Token token) {
2029        final int tokenIndex = token.getTokenIndex();
2030        final List<Token> tokensToLeft =
2031                tokens.getHiddenTokensToLeft(tokenIndex, JavaLanguageLexer.COMMENTS);
2032        final List<Token> tokensToRight =
2033                tokens.getHiddenTokensToRight(tokenIndex, JavaLanguageLexer.COMMENTS);
2034
2035        final DetailAstImpl detailAst = new DetailAstImpl();
2036        detailAst.initialize(token);
2037        if (tokensToLeft != null) {
2038            detailAst.setHiddenBefore(tokensToLeft);
2039        }
2040        if (tokensToRight != null) {
2041            detailAst.setHiddenAfter(tokensToRight);
2042        }
2043        return detailAst;
2044    }
2045
2046    /**
2047     * Create a DetailAstImpl from a given TerminalNode. This method should be
2048     * used for terminal nodes, i.e. {@code @}.
2049     *
2050     * @param node the TerminalNode to build the DetailAstImpl from
2051     * @return new DetailAstImpl of given type
2052     */
2053    private DetailAstImpl create(TerminalNode node) {
2054        return create((Token) node.getPayload());
2055    }
2056
2057    /**
2058     * Creates a type declaration DetailAstImpl from a given rule context.
2059     *
2060     * @param ctx ParserRuleContext we are in
2061     * @param type the type declaration to create
2062     * @param modifierList respective modifiers
2063     * @return type declaration DetailAstImpl
2064     */
2065    private DetailAstImpl createTypeDeclaration(ParserRuleContext ctx, int type,
2066                                                List<? extends ParseTree> modifierList) {
2067        final DetailAstImpl typeDeclaration = createImaginary(type);
2068        typeDeclaration.addChild(createModifiers(modifierList));
2069        processChildren(typeDeclaration, ctx.children);
2070        return typeDeclaration;
2071    }
2072
2073    /**
2074     * Builds the modifiers AST.
2075     *
2076     * @param modifierList the list of modifier contexts
2077     * @return "MODIFIERS" ast
2078     */
2079    private DetailAstImpl createModifiers(List<? extends ParseTree> modifierList) {
2080        final DetailAstImpl mods = createImaginary(TokenTypes.MODIFIERS);
2081        processChildren(mods, modifierList);
2082        return mods;
2083    }
2084
2085    /**
2086     * Add new sibling to the end of existing siblings.
2087     *
2088     * @param self DetailAstImpl to add last sibling to
2089     * @param sibling DetailAstImpl sibling to add
2090     */
2091    private static void addLastSibling(DetailAstImpl self, DetailAstImpl sibling) {
2092        DetailAstImpl nextSibling = self;
2093        if (nextSibling != null) {
2094            while (nextSibling.getNextSibling() != null) {
2095                nextSibling = nextSibling.getNextSibling();
2096            }
2097            nextSibling.setNextSibling(sibling);
2098        }
2099    }
2100
2101    @Override
2102    public DetailAstImpl visit(ParseTree tree) {
2103        DetailAstImpl ast = null;
2104        if (tree != null) {
2105            ast = tree.accept(this);
2106        }
2107        return ast;
2108    }
2109
2110    /**
2111     * Used to swap and organize DetailAstImpl subtrees.
2112     */
2113    private static final class DetailAstPair {
2114
2115        /** The root DetailAstImpl of this pair. */
2116        private DetailAstImpl root;
2117
2118        /** The child (potentially with siblings) of this pair. */
2119        private DetailAstImpl child;
2120
2121        /**
2122         * Moves child reference to the last child.
2123         */
2124        private void advanceChildToEnd() {
2125            while (child.getNextSibling() != null) {
2126                child = child.getNextSibling();
2127            }
2128        }
2129
2130        /**
2131         * Returns the root node.
2132         *
2133         * @return the root node
2134         */
2135        private DetailAstImpl getRoot() {
2136            return root;
2137        }
2138
2139        /**
2140         * This method is used to replace the {@code ^} (set as root node) ANTLR2
2141         * operator.
2142         *
2143         * @param pair the DetailAstPair to use for swapping nodes
2144         * @param ast the new root
2145         */
2146        private static void makeAstRoot(DetailAstPair pair, DetailAstImpl ast) {
2147            ast.addChild(pair.root);
2148            pair.child = pair.root;
2149            pair.advanceChildToEnd();
2150            pair.root = ast;
2151        }
2152
2153        /**
2154         * Adds a child (or new root) to the given DetailAstPair.
2155         *
2156         * @param pair the DetailAstPair to add child to
2157         * @param ast the child to add
2158         */
2159        private static void addAstChild(DetailAstPair pair, DetailAstImpl ast) {
2160            if (ast != null) {
2161                if (pair.root == null) {
2162                    pair.root = ast;
2163                }
2164                else {
2165                    pair.child.setNextSibling(ast);
2166                }
2167                pair.child = ast;
2168                pair.advanceChildToEnd();
2169            }
2170        }
2171    }
2172}