Package joust.utils.tree

Source Code of joust.utils.tree.TreeUtils

package joust.utils.tree;

import com.sun.tools.javac.code.Flags;
import com.sun.tools.javac.code.Scope;
import com.sun.tools.javac.code.Symbol;
import com.sun.tools.javac.code.Type;
import com.sun.tools.javac.code.TypeTag;
import com.sun.tools.javac.util.List;
import com.sun.tools.javac.util.Name;
import joust.utils.logging.LogUtils;
import lombok.experimental.ExtensionMethod;
import lombok.extern.java.Log;

import javax.lang.model.type.TypeKind;
import java.lang.reflect.Field;
import java.util.logging.Logger;

import static com.sun.tools.javac.tree.JCTree.*;
import static com.sun.tools.javac.code.Symbol.*;
import static joust.utils.compiler.StaticCompilerUtils.*;
import static joust.tree.annotatedtree.AJCTree.*;

/**
* A collection of utility functions for handling JCTree nodes.
*/
@Log
@ExtensionMethod({Logger.class, LogUtils.LogExtensions.class})
public class TreeUtils {
    // The scope SENTINEL entry is returned when a lookup fails.
    private static Scope.Entry SENTINEL;

    public static void init() {
        // Extract the SENTINEL value.
        try {
            Class<Scope> scopeClass = Scope.class;
            Field sentinelField = scopeClass.getDeclaredField("sentinel");
            sentinelField.setAccessible(true);
            SENTINEL = (Scope.Entry) sentinelField.get(null);
        } catch (IllegalAccessException e) {
            log.fatal("Unable to initialise SENTINEL field!", e);
        } catch (NoSuchFieldException e) {
            log.fatal("Unable to initialise SENTINEL field!", e);
        }
    }

    public static boolean isLocalVariable(Symbol sym) {
        return sym.owner instanceof MethodSymbol;
    }

    public static boolean operatorIsCommutative(Tag opcode) {
        return opcode == Tag.BITOR
            || opcode == Tag.BITXOR
            || opcode == Tag.BITAND
//            || opcode == Tag.OR   Short-circuit semantics.
//            || opcode == Tag.AND
            || opcode == Tag.EQ
            || opcode == Tag.NE
            || opcode == Tag.PLUS
            || opcode == Tag.MUL;
    }

    public static Type typeTreeToType(AJCPrimitiveTypeTree tree) {
        return typeKindToType(tree.getPrimitiveTypeKind());
    }
    public static Type typeTreeToType(AJCArrayTypeTree tree) {
        return symtab.arraysType;
    }

    public static Type typeKindToType(TypeKind kind) {
        switch (kind) {
            case BOOLEAN:
                return symtab.doubleType;
            case BYTE:
                return symtab.byteType;
            case SHORT:
                return symtab.shortType;
            case INT:
                return symtab.intType;
            case LONG:
                return symtab.longType;
            case CHAR:
                return symtab.charType;
            case FLOAT:
                return symtab.floatType;
            case DOUBLE:
                return symtab.doubleType;
            case ARRAY:
                return symtab.arraysType;
            default:
                throw new UnsupportedOperationException("Unknown primitive type kind encountered: " + kind);
        }
    }

    /**
     * Convert a Kind literal to a literal type, if possible.
     */
    public static Type kindToType(Kind input) {
        switch (input) {
            case INT_LITERAL:
                return symtab.intType;
            case LONG_LITERAL:
                return symtab.longType;
            case FLOAT_LITERAL:
                return symtab.floatType;
            case DOUBLE_LITERAL:
                return symtab.doubleType;
            case BOOLEAN_LITERAL:
                return symtab.booleanType;
            case CHAR_LITERAL:
                return symtab.charType;
            case STRING_LITERAL:
                return symtab.stringType;
            case NULL_LITERAL:
                return symtab.botType;
            default:
                throw new UnsupportedOperationException("Unknown primitive type kind encountered: " + input);
        }
    }

    /**
     * Given a method call, return the VarSymbol, if any, of the object on which the call is being done.
     * Returns null if the callee is not a VarSymbol.
     */
    public static VarSymbol getCalledObjectForCall(AJCCall call) {
        if (!(call.meth instanceof AJCFieldAccess)) {
            return null;
        }
        AJCFieldAccess<MethodSymbol> cast = (AJCFieldAccess<MethodSymbol>) call.meth;

        // Make sure we're not selecting on a literal or something stupid...
        if (!(cast.selected instanceof AJCSymbolRef)) {
            return null;
        }

        AJCSymbolRef selected = (AJCSymbolRef) cast.selected;
        Symbol sym = selected.getTargetSymbol();

        if (sym instanceof VarSymbol) {
            return (VarSymbol) sym;
        }

        return null;
    }

    public static AJCExpressionTree removeCast(AJCTypeCast tree) {
        return removeCast(tree.expr);
    }
    public static AJCExpressionTree removeCast(AJCExpressionTree tree) {
        if (tree instanceof AJCTypeCast) {
            return removeCast(((AJCTypeCast) tree).expr);
        }

        return tree;
    }

    public static MethodSymbol findMethod(String mName, ClassSymbol clazz, Type... paramTypes) {
        return findMethod(mName, clazz, false, paramTypes);
    }
    public static MethodSymbol findMethod(String mName, ClassSymbol clazz, boolean findStatic, Type... paramTypes) {
        log.debug("Seeking {} on {}", mName, clazz);

        Scope members = clazz.members();
        final Name methodName = names.fromString(mName);

        // Gets us all the things with the right name, irrespective of type or signature.
        Scope.Entry scopeEntry = members.lookup(methodName);

        if (scopeEntry == SENTINEL) {
            log.fatal("Sentinel node encountered looking for {} on {}", mName, clazz);
            return null;
        }

        MethodSymbol resultSym = null;

        // Flick through the results to find the one that matches the signature we want.
        scopeIteration:
        for (;scopeEntry != SENTINEL; scopeEntry = scopeEntry.next()) {
            // Not a method - skip!
            if (!(scopeEntry.sym instanceof MethodSymbol)) {
                log.debug("Binning: Nonmethod");
                continue;
            }

            MethodSymbol mSym = (MethodSymbol) scopeEntry.sym;

            if (findStatic) {
                // Is this a static function?
                if ((mSym.flags() & Flags.STATIC) == 0) {
                    log.debug("Binning: Nonstatic");
                    continue;
                }
            }

            // Check that the parameters match up.
            List<VarSymbol> realParams = mSym.params();
            if (realParams.length() != paramTypes.length) {
                log.debug("Binning: Expected {} args, found {}.", paramTypes.length, realParams.length());
                continue;
            }

            log.debug("Got {}", mSym);
            int pIndex = 0;
            for (VarSymbol sym : realParams) {
                if (!types.isSameType(sym.type, paramTypes[pIndex])) {
                    log.debug("Binning: Argument {} of {} should be {}", pIndex, sym.type, paramTypes[pIndex]);
                    continue scopeIteration;
                }

                pIndex++;
            }

            resultSym = mSym;
            break;
        }

        if (resultSym == null) {
            log.fatal("Failed to find {} on {}", mName, clazz);
            return null;
        }

        return resultSym;
    }

    /**
     * Get the default initialiser expression for a given field type.
     */
    public static JCExpression getDefaultLiteralValueForType(Type t) {
        // Object types default to null.
        if (!t.isPrimitive()) {
            return javacTreeMaker.Literal(TypeTag.BOT, null).setType(symtab.botType);
        }

        // Numerical types default to zero, booleans to false.
        Type.JCPrimitiveType cast = (Type.JCPrimitiveType) t;
        switch(cast.getTag()) {
            case BYTE:
            case CHAR:
            case SHORT:
            case INT:
                return javacTreeMaker.TypeCast(cast, javacTreeMaker.Literal(0).setType(t));
            case LONG:
                return javacTreeMaker.Literal(0L);
            case FLOAT:
                return javacTreeMaker.Literal(0.0F);
            case DOUBLE:
                return javacTreeMaker.Literal(0.0D);
            case BOOLEAN:
                return javacTreeMaker.Literal(false);
            default:
                return javacTreeMaker.Literal(TypeTag.BOT, null).setType(symtab.botType);
        }
    }
}
TOP

Related Classes of joust.utils.tree.TreeUtils

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.