All Downloads are FREE. Search and download functionalities are using the official Maven repository.

javacutil.src.org.checkerframework.javacutil.trees.TreeBuilder Maven / Gradle / Ivy

Go to download

The Checker Framework enhances Java’s type system to make it more powerful and useful. This lets software developers detect and prevent errors in their Java programs. The Checker Framework includes compiler plug-ins ("checkers") that find bugs or verify their absence. It also permits you to write your own compiler plug-ins.

There is a newer version: 3.42.0
Show newest version
package org.checkerframework.javacutil.trees;

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;

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;

/**
 * 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.nil(),
                                (Type)iteratorType,
                                com.sun.tools.javac.util.List.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.nil(),
                                elementType,
                                com.sun.tools.javac.util.List.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 < 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 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 < 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;
    }

}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy