aboutsummaryrefslogtreecommitdiffhomepage
path: root/third_party/checker_framework_javacutil/java/org/checkerframework/javacutil/trees/TreeBuilder.java
blob: eab005dea809cef391d9ce2526ca24f3a9d7aced (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
package org.checkerframework.javacutil.trees;

import com.sun.source.tree.ArrayAccessTree;
import com.sun.source.tree.AssignmentTree;
import com.sun.source.tree.BinaryTree;
import com.sun.source.tree.ExpressionTree;
import com.sun.source.tree.IdentifierTree;
import com.sun.source.tree.LiteralTree;
import com.sun.source.tree.MemberSelectTree;
import com.sun.source.tree.MethodInvocationTree;
import com.sun.source.tree.StatementTree;
import com.sun.source.tree.Tree;
import com.sun.source.tree.TypeCastTree;
import com.sun.source.tree.VariableTree;
import com.sun.tools.javac.code.Symbol;
import com.sun.tools.javac.code.Symtab;
import com.sun.tools.javac.code.Type;
import com.sun.tools.javac.processing.JavacProcessingEnvironment;
import com.sun.tools.javac.tree.JCTree;
import com.sun.tools.javac.tree.TreeInfo;
import com.sun.tools.javac.tree.TreeMaker;
import com.sun.tools.javac.util.Context;
import com.sun.tools.javac.util.Names;
import java.util.List;
import javax.annotation.processing.ProcessingEnvironment;
import javax.lang.model.element.Element;
import javax.lang.model.element.ExecutableElement;
import javax.lang.model.element.Name;
import javax.lang.model.element.TypeElement;
import javax.lang.model.element.VariableElement;
import javax.lang.model.type.ArrayType;
import javax.lang.model.type.DeclaredType;
import javax.lang.model.type.TypeKind;
import javax.lang.model.type.TypeMirror;
import javax.lang.model.util.ElementFilter;
import javax.lang.model.util.Elements;
import javax.lang.model.util.Types;
import org.checkerframework.javacutil.InternalUtils;
import org.checkerframework.javacutil.TypesUtils;

/**
 * The TreeBuilder permits the creation of new AST Trees using the non-public Java compiler API
 * TreeMaker.
 */
public class TreeBuilder {
    protected final Elements elements;
    protected final Types modelTypes;
    protected final com.sun.tools.javac.code.Types javacTypes;
    protected final TreeMaker maker;
    protected final Names names;
    protected final Symtab symtab;
    protected final ProcessingEnvironment env;

    public TreeBuilder(ProcessingEnvironment env) {
        this.env = env;
        Context context = ((JavacProcessingEnvironment) env).getContext();
        elements = env.getElementUtils();
        modelTypes = env.getTypeUtils();
        javacTypes = com.sun.tools.javac.code.Types.instance(context);
        maker = TreeMaker.instance(context);
        names = Names.instance(context);
        symtab = Symtab.instance(context);
    }

    /**
     * Builds an AST Tree to access the iterator() method of some iterable expression.
     *
     * @param iterableExpr an expression whose type is a subtype of Iterable
     * @return a MemberSelectTree that accesses the iterator() method of the expression
     */
    public MemberSelectTree buildIteratorMethodAccess(ExpressionTree iterableExpr) {
        DeclaredType exprType =
                (DeclaredType) TypesUtils.upperBound(InternalUtils.typeOf(iterableExpr));
        assert exprType != null : "expression must be of declared type Iterable<>";

        TypeElement exprElement = (TypeElement) exprType.asElement();

        // Find the iterator() method of the iterable type
        Symbol.MethodSymbol iteratorMethod = null;

        for (ExecutableElement method :
                ElementFilter.methodsIn(elements.getAllMembers(exprElement))) {
            Name methodName = method.getSimpleName();

            if (method.getParameters().size() == 0) {
                if (methodName.contentEquals("iterator")) {
                    iteratorMethod = (Symbol.MethodSymbol) method;
                }
            }
        }

        assert iteratorMethod != null : "no iterator method declared for expression type";

        Type.MethodType methodType = (Type.MethodType) iteratorMethod.asType();
        Symbol.TypeSymbol methodClass = methodType.asElement();
        DeclaredType iteratorType = (DeclaredType) methodType.getReturnType();
        TypeMirror elementType;

        if (iteratorType.getTypeArguments().size() > 0) {
            elementType = iteratorType.getTypeArguments().get(0);
            // Remove captured type from a wildcard.
            if (elementType instanceof Type.CapturedType) {
                elementType = ((Type.CapturedType) elementType).wildcard;
            }

            iteratorType =
                    modelTypes.getDeclaredType(
                            (TypeElement) modelTypes.asElement(iteratorType), elementType);
        }

        // Replace the iterator method's generic return type with
        // the actual element type of the expression.
        Type.MethodType updatedMethodType =
                new Type.MethodType(
                        com.sun.tools.javac.util.List.<Type>nil(),
                        (Type) iteratorType,
                        com.sun.tools.javac.util.List.<Type>nil(),
                        methodClass);

        JCTree.JCFieldAccess iteratorAccess =
                (JCTree.JCFieldAccess)
                        maker.Select((JCTree.JCExpression) iterableExpr, iteratorMethod);
        iteratorAccess.setType(updatedMethodType);

        return iteratorAccess;
    }

    /**
     * Builds an AST Tree to access the hasNext() method of an iterator.
     *
     * @param iteratorExpr an expression whose type is a subtype of Iterator
     * @return a MemberSelectTree that accesses the hasNext() method of the expression
     */
    public MemberSelectTree buildHasNextMethodAccess(ExpressionTree iteratorExpr) {
        DeclaredType exprType = (DeclaredType) InternalUtils.typeOf(iteratorExpr);
        assert exprType != null : "expression must be of declared type Iterator<>";

        TypeElement exprElement = (TypeElement) exprType.asElement();

        // Find the hasNext() method of the iterator type
        Symbol.MethodSymbol hasNextMethod = null;

        for (ExecutableElement method :
                ElementFilter.methodsIn(elements.getAllMembers(exprElement))) {
            Name methodName = method.getSimpleName();

            if (method.getParameters().size() == 0) {
                if (methodName.contentEquals("hasNext")) {
                    hasNextMethod = (Symbol.MethodSymbol) method;
                }
            }
        }

        assert hasNextMethod != null : "no hasNext method declared for expression type";

        JCTree.JCFieldAccess hasNextAccess =
                (JCTree.JCFieldAccess)
                        maker.Select((JCTree.JCExpression) iteratorExpr, hasNextMethod);
        hasNextAccess.setType(hasNextMethod.asType());

        return hasNextAccess;
    }

    /**
     * Builds an AST Tree to access the next() method of an iterator.
     *
     * @param iteratorExpr an expression whose type is a subtype of Iterator
     * @return a MemberSelectTree that accesses the next() method of the expression
     */
    public MemberSelectTree buildNextMethodAccess(ExpressionTree iteratorExpr) {
        DeclaredType exprType = (DeclaredType) InternalUtils.typeOf(iteratorExpr);
        assert exprType != null : "expression must be of declared type Iterator<>";

        TypeElement exprElement = (TypeElement) exprType.asElement();

        // Find the next() method of the iterator type
        Symbol.MethodSymbol nextMethod = null;

        for (ExecutableElement method :
                ElementFilter.methodsIn(elements.getAllMembers(exprElement))) {
            Name methodName = method.getSimpleName();

            if (method.getParameters().size() == 0) {
                if (methodName.contentEquals("next")) {
                    nextMethod = (Symbol.MethodSymbol) method;
                }
            }
        }

        assert nextMethod != null : "no next method declared for expression type";

        Type.MethodType methodType = (Type.MethodType) nextMethod.asType();
        Symbol.TypeSymbol methodClass = methodType.asElement();
        Type elementType;

        if (exprType.getTypeArguments().size() > 0) {
            elementType = (Type) exprType.getTypeArguments().get(0);
        } else {
            elementType = symtab.objectType;
        }

        // Replace the next method's generic return type with
        // the actual element type of the expression.
        Type.MethodType updatedMethodType =
                new Type.MethodType(
                        com.sun.tools.javac.util.List.<Type>nil(),
                        elementType,
                        com.sun.tools.javac.util.List.<Type>nil(),
                        methodClass);

        JCTree.JCFieldAccess nextAccess =
                (JCTree.JCFieldAccess) maker.Select((JCTree.JCExpression) iteratorExpr, nextMethod);
        nextAccess.setType(updatedMethodType);

        return nextAccess;
    }

    /**
     * Builds an AST Tree to dereference the length field of an array
     *
     * @param expression the array expression whose length is being accessed
     * @return a MemberSelectTree to dereference the length of the array
     */
    public MemberSelectTree buildArrayLengthAccess(ExpressionTree expression) {

        return (JCTree.JCFieldAccess)
                maker.Select((JCTree.JCExpression) expression, symtab.lengthVar);
    }

    /**
     * Builds an AST Tree to call a method designated by the argument expression.
     *
     * @param methodExpr an expression denoting a method with no arguments
     * @return a MethodInvocationTree to call the argument method
     */
    public MethodInvocationTree buildMethodInvocation(ExpressionTree methodExpr) {
        return maker.App((JCTree.JCExpression) methodExpr);
    }

    /**
     * Builds an AST Tree to call a method designated by methodExpr, with one argument designated by
     * argExpr.
     *
     * @param methodExpr an expression denoting a method with one argument
     * @param argExpr an expression denoting an argument to the method
     * @return a MethodInvocationTree to call the argument method
     */
    public MethodInvocationTree buildMethodInvocation(
            ExpressionTree methodExpr, ExpressionTree argExpr) {
        return maker.App(
                (JCTree.JCExpression) methodExpr,
                com.sun.tools.javac.util.List.of((JCTree.JCExpression) argExpr));
    }

    /**
     * Builds an AST Tree to declare and initialize a variable, with no modifiers.
     *
     * @param type the type of the variable
     * @param name the name of the variable
     * @param owner the element containing the new symbol
     * @param initializer the initializer expression
     * @return a VariableDeclTree declaring the new variable
     */
    public VariableTree buildVariableDecl(
            TypeMirror type, String name, Element owner, ExpressionTree initializer) {
        DetachedVarSymbol sym =
                new DetachedVarSymbol(0, names.fromString(name), (Type) type, (Symbol) owner);
        VariableTree tree = maker.VarDef(sym, (JCTree.JCExpression) initializer);
        sym.setDeclaration(tree);
        return tree;
    }

    /**
     * Builds an AST Tree to declare and initialize a variable. The type of the variable is
     * specified by a Tree.
     *
     * @param type the type of the variable, as a Tree
     * @param name the name of the variable
     * @param owner the element containing the new symbol
     * @param initializer the initializer expression
     * @return a VariableDeclTree declaring the new variable
     */
    public VariableTree buildVariableDecl(
            Tree type, String name, Element owner, ExpressionTree initializer) {
        Type typeMirror = (Type) InternalUtils.typeOf(type);
        DetachedVarSymbol sym =
                new DetachedVarSymbol(0, names.fromString(name), typeMirror, (Symbol) owner);
        JCTree.JCModifiers mods = maker.Modifiers(0);
        JCTree.JCVariableDecl decl =
                maker.VarDef(
                        mods,
                        sym.name,
                        (JCTree.JCExpression) type,
                        (JCTree.JCExpression) initializer);
        decl.setType(typeMirror);
        decl.sym = sym;
        sym.setDeclaration(decl);
        return decl;
    }

    /**
     * Builds an AST Tree to refer to a variable.
     *
     * @param decl the declaration of the variable
     * @return an IdentifierTree to refer to the variable
     */
    public IdentifierTree buildVariableUse(VariableTree decl) {
        return (IdentifierTree) maker.Ident((JCTree.JCVariableDecl) decl);
    }

    /**
     * Builds an AST Tree to cast the type of an expression.
     *
     * @param type the type to cast to
     * @param expr the expression to be cast
     * @return a cast of the expression to the type
     */
    public TypeCastTree buildTypeCast(TypeMirror type, ExpressionTree expr) {
        return maker.TypeCast((Type) type, (JCTree.JCExpression) expr);
    }

    /**
     * Builds an AST Tree to assign an expression to a variable.
     *
     * @param variable the declaration of the variable to assign to
     * @param expr the expression to be assigned
     * @return a statement assigning the expression to the variable
     */
    public StatementTree buildAssignment(VariableTree variable, ExpressionTree expr) {
        return maker.Assignment(TreeInfo.symbolFor((JCTree) variable), (JCTree.JCExpression) expr);
    }

    /**
     * Builds an AST Tree to assign an RHS expression to an LHS expression.
     *
     * @param lhs the expression to be assigned to
     * @param rhs the expression to be assigned
     * @return a statement assigning the expression to the variable
     */
    public AssignmentTree buildAssignment(ExpressionTree lhs, ExpressionTree rhs) {
        JCTree.JCAssign assign = maker.Assign((JCTree.JCExpression) lhs, (JCTree.JCExpression) rhs);
        assign.setType((Type) InternalUtils.typeOf(lhs));
        return assign;
    }

    /** Builds an AST Tree representing a literal value of primitive or String type. */
    public LiteralTree buildLiteral(Object value) {
        return maker.Literal(value);
    }

    /**
     * Builds an AST Tree to compare two operands with less than.
     *
     * @param left the left operand tree
     * @param right the right operand tree
     * @return a Tree representing "left &lt; right"
     */
    public BinaryTree buildLessThan(ExpressionTree left, ExpressionTree right) {
        JCTree.JCBinary binary =
                maker.Binary(
                        JCTree.Tag.LT, (JCTree.JCExpression) left, (JCTree.JCExpression) right);
        binary.setType((Type) modelTypes.getPrimitiveType(TypeKind.BOOLEAN));
        return binary;
    }

    /**
     * Builds an AST Tree to dereference an array.
     *
     * @param array the array to dereference
     * @param index the index at which to dereference
     * @return a Tree representing the dereference
     */
    public ArrayAccessTree buildArrayAccess(ExpressionTree array, ExpressionTree index) {
        ArrayType arrayType = (ArrayType) InternalUtils.typeOf(array);
        JCTree.JCArrayAccess access =
                maker.Indexed((JCTree.JCExpression) array, (JCTree.JCExpression) index);
        access.setType((Type) arrayType.getComponentType());
        return access;
    }

    /**
     * Builds an AST Tree to refer to a class name.
     *
     * @param elt an element representing the class
     * @return an IdentifierTree referring to the class
     */
    public IdentifierTree buildClassUse(Element elt) {
        return maker.Ident((Symbol) elt);
    }

    /**
     * Builds an AST Tree to access the valueOf() method of boxed type such as Short or Float.
     *
     * @param expr an expression whose type is a boxed type
     * @return a MemberSelectTree that accesses the valueOf() method of the expression
     */
    public MemberSelectTree buildValueOfMethodAccess(Tree expr) {
        TypeMirror boxedType = InternalUtils.typeOf(expr);

        assert TypesUtils.isBoxedPrimitive(boxedType);

        // Find the valueOf(unboxedType) method of the boxed type
        Symbol.MethodSymbol valueOfMethod = getValueOfMethod(env, boxedType);

        Type.MethodType methodType = (Type.MethodType) valueOfMethod.asType();

        JCTree.JCFieldAccess valueOfAccess =
                (JCTree.JCFieldAccess) maker.Select((JCTree.JCExpression) expr, valueOfMethod);
        valueOfAccess.setType(methodType);

        return valueOfAccess;
    }

    /** Returns the valueOf method of a boxed type such as Short or Float. */
    public static Symbol.MethodSymbol getValueOfMethod(
            ProcessingEnvironment env, TypeMirror boxedType) {
        Symbol.MethodSymbol valueOfMethod = null;

        TypeMirror unboxedType = env.getTypeUtils().unboxedType(boxedType);
        TypeElement boxedElement = (TypeElement) ((DeclaredType) boxedType).asElement();
        for (ExecutableElement method :
                ElementFilter.methodsIn(env.getElementUtils().getAllMembers(boxedElement))) {
            Name methodName = method.getSimpleName();

            if (methodName.contentEquals("valueOf")) {
                List<? extends VariableElement> params = method.getParameters();
                if (params.size() == 1
                        && env.getTypeUtils().isSameType(params.get(0).asType(), unboxedType)) {
                    valueOfMethod = (Symbol.MethodSymbol) method;
                }
            }
        }

        assert valueOfMethod != null : "no valueOf method declared for boxed type";
        return valueOfMethod;
    }

    /**
     * Builds an AST Tree to access the *Value() method of a boxed type such as Short or Float,
     * where * is the corresponding primitive type (i.e. shortValue or floatValue).
     *
     * @param expr an expression whose type is a boxed type
     * @return a MemberSelectTree that accesses the *Value() method of the expression
     */
    public MemberSelectTree buildPrimValueMethodAccess(Tree expr) {
        TypeMirror boxedType = InternalUtils.typeOf(expr);
        TypeElement boxedElement = (TypeElement) ((DeclaredType) boxedType).asElement();

        assert TypesUtils.isBoxedPrimitive(boxedType);
        TypeMirror unboxedType = modelTypes.unboxedType(boxedType);

        // Find the *Value() method of the boxed type
        String primValueName = unboxedType.toString() + "Value";
        Symbol.MethodSymbol primValueMethod = null;

        for (ExecutableElement method :
                ElementFilter.methodsIn(elements.getAllMembers(boxedElement))) {
            Name methodName = method.getSimpleName();

            if (methodName.contentEquals(primValueName) && method.getParameters().size() == 0) {
                primValueMethod = (Symbol.MethodSymbol) method;
            }
        }

        assert primValueMethod != null : "no *Value method declared for boxed type";

        Type.MethodType methodType = (Type.MethodType) primValueMethod.asType();

        JCTree.JCFieldAccess primValueAccess =
                (JCTree.JCFieldAccess) maker.Select((JCTree.JCExpression) expr, primValueMethod);
        primValueAccess.setType(methodType);

        return primValueAccess;
    }

    /** Map public AST Tree.Kinds to internal javac JCTree.Tags. */
    public JCTree.Tag kindToTag(Tree.Kind kind) {
        switch (kind) {
            case AND:
                return JCTree.Tag.BITAND;
            case AND_ASSIGNMENT:
                return JCTree.Tag.BITAND_ASG;
            case ANNOTATION:
                return JCTree.Tag.ANNOTATION;
            case ANNOTATION_TYPE:
                return JCTree.Tag.TYPE_ANNOTATION;
            case ARRAY_ACCESS:
                return JCTree.Tag.INDEXED;
            case ARRAY_TYPE:
                return JCTree.Tag.TYPEARRAY;
            case ASSERT:
                return JCTree.Tag.ASSERT;
            case ASSIGNMENT:
                return JCTree.Tag.ASSIGN;
            case BITWISE_COMPLEMENT:
                return JCTree.Tag.COMPL;
            case BLOCK:
                return JCTree.Tag.BLOCK;
            case BREAK:
                return JCTree.Tag.BREAK;
            case CASE:
                return JCTree.Tag.CASE;
            case CATCH:
                return JCTree.Tag.CATCH;
            case CLASS:
                return JCTree.Tag.CLASSDEF;
            case CONDITIONAL_AND:
                return JCTree.Tag.AND;
            case CONDITIONAL_EXPRESSION:
                return JCTree.Tag.CONDEXPR;
            case CONDITIONAL_OR:
                return JCTree.Tag.OR;
            case CONTINUE:
                return JCTree.Tag.CONTINUE;
            case DIVIDE:
                return JCTree.Tag.DIV;
            case DIVIDE_ASSIGNMENT:
                return JCTree.Tag.DIV_ASG;
            case DO_WHILE_LOOP:
                return JCTree.Tag.DOLOOP;
            case ENHANCED_FOR_LOOP:
                return JCTree.Tag.FOREACHLOOP;
            case EQUAL_TO:
                return JCTree.Tag.EQ;
            case EXPRESSION_STATEMENT:
                return JCTree.Tag.EXEC;
            case FOR_LOOP:
                return JCTree.Tag.FORLOOP;
            case GREATER_THAN:
                return JCTree.Tag.GT;
            case GREATER_THAN_EQUAL:
                return JCTree.Tag.GE;
            case IDENTIFIER:
                return JCTree.Tag.IDENT;
            case IF:
                return JCTree.Tag.IF;
            case IMPORT:
                return JCTree.Tag.IMPORT;
            case INSTANCE_OF:
                return JCTree.Tag.TYPETEST;
            case LABELED_STATEMENT:
                return JCTree.Tag.LABELLED;
            case LEFT_SHIFT:
                return JCTree.Tag.SL;
            case LEFT_SHIFT_ASSIGNMENT:
                return JCTree.Tag.SL_ASG;
            case LESS_THAN:
                return JCTree.Tag.LT;
            case LESS_THAN_EQUAL:
                return JCTree.Tag.LE;
            case LOGICAL_COMPLEMENT:
                return JCTree.Tag.NOT;
            case MEMBER_SELECT:
                return JCTree.Tag.SELECT;
            case METHOD:
                return JCTree.Tag.METHODDEF;
            case METHOD_INVOCATION:
                return JCTree.Tag.APPLY;
            case MINUS:
                return JCTree.Tag.MINUS;
            case MINUS_ASSIGNMENT:
                return JCTree.Tag.MINUS_ASG;
            case MODIFIERS:
                return JCTree.Tag.MODIFIERS;
            case MULTIPLY:
                return JCTree.Tag.MUL;
            case MULTIPLY_ASSIGNMENT:
                return JCTree.Tag.MUL_ASG;
            case NEW_ARRAY:
                return JCTree.Tag.NEWARRAY;
            case NEW_CLASS:
                return JCTree.Tag.NEWCLASS;
            case NOT_EQUAL_TO:
                return JCTree.Tag.NE;
            case OR:
                return JCTree.Tag.BITOR;
            case OR_ASSIGNMENT:
                return JCTree.Tag.BITOR_ASG;
            case PARENTHESIZED:
                return JCTree.Tag.PARENS;
            case PLUS:
                return JCTree.Tag.PLUS;
            case PLUS_ASSIGNMENT:
                return JCTree.Tag.PLUS_ASG;
            case POSTFIX_DECREMENT:
                return JCTree.Tag.POSTDEC;
            case POSTFIX_INCREMENT:
                return JCTree.Tag.POSTINC;
            case PREFIX_DECREMENT:
                return JCTree.Tag.PREDEC;
            case PREFIX_INCREMENT:
                return JCTree.Tag.PREINC;
            case REMAINDER:
                return JCTree.Tag.MOD;
            case REMAINDER_ASSIGNMENT:
                return JCTree.Tag.MOD_ASG;
            case RETURN:
                return JCTree.Tag.RETURN;
            case RIGHT_SHIFT:
                return JCTree.Tag.SR;
            case RIGHT_SHIFT_ASSIGNMENT:
                return JCTree.Tag.SR_ASG;
            case SWITCH:
                return JCTree.Tag.SWITCH;
            case SYNCHRONIZED:
                return JCTree.Tag.SYNCHRONIZED;
            case THROW:
                return JCTree.Tag.THROW;
            case TRY:
                return JCTree.Tag.TRY;
            case TYPE_CAST:
                return JCTree.Tag.TYPECAST;
            case TYPE_PARAMETER:
                return JCTree.Tag.TYPEPARAMETER;
            case UNARY_MINUS:
                return JCTree.Tag.NEG;
            case UNARY_PLUS:
                return JCTree.Tag.POS;
            case UNION_TYPE:
                return JCTree.Tag.TYPEUNION;
            case UNSIGNED_RIGHT_SHIFT:
                return JCTree.Tag.USR;
            case UNSIGNED_RIGHT_SHIFT_ASSIGNMENT:
                return JCTree.Tag.USR_ASG;
            case VARIABLE:
                return JCTree.Tag.VARDEF;
            case WHILE_LOOP:
                return JCTree.Tag.WHILELOOP;
            case XOR:
                return JCTree.Tag.BITXOR;
            case XOR_ASSIGNMENT:
                return JCTree.Tag.BITXOR_ASG;
            default:
                return JCTree.Tag.NO_TAG;
        }
    }

    /**
     * Builds an AST Tree to perform a binary operation.
     *
     * @param type result type of the operation
     * @param op AST Tree operator
     * @param left the left operand tree
     * @param right the right operand tree
     * @return a Tree representing "left &lt; right"
     */
    public BinaryTree buildBinary(
            TypeMirror type, Tree.Kind op, ExpressionTree left, ExpressionTree right) {
        JCTree.Tag jcOp = kindToTag(op);
        JCTree.JCBinary binary =
                maker.Binary(jcOp, (JCTree.JCExpression) left, (JCTree.JCExpression) right);
        binary.setType((Type) type);
        return binary;
    }
}